Hệ thống loại của Haskell có chính thức tương đương với Java không? [đóng cửa]


66

Tôi nhận ra một số điều dễ hơn / khó hơn trong một ngôn ngữ so với ngôn ngữ khác, nhưng tôi chỉ quan tâm đến các tính năng liên quan đến loại có thể có trong một ngôn ngữ và không thể / không liên quan ở ngôn ngữ kia. Để làm cho nó cụ thể hơn, hãy bỏ qua các tiện ích mở rộng loại Haskell vì có rất nhiều thứ ngoài kia làm tất cả các loại công cụ điên rồ / tuyệt vời.


4
Tôi cũng tò mò muốn nghe các nhà lý thuyết thể loại dài ngoằn ngoèo trả lời cho câu hỏi này; mặc dù tôi nghi ngờ tôi sẽ đặc biệt hiểu nó, tôi vẫn quan tâm đến một chi tiết về điều này. Độ nghiêng của tôi từ những điều tôi đã đọc là các hệ thống kiểu HM cho phép trình biên dịch biết một tấn về những gì mã của bạn làm đó là lý do nó có khả năng suy luận loại quá nhiều cũng như đưa ra rất nhiều bảo đảm về hành vi. Nhưng đó chỉ là bản năng ruột thịt của tôi và tôi chắc chắn có những thứ khác mà tôi hoàn toàn không biết.
Jimmy Hoffa

1
Đây là một câu hỏi hay - thời gian để tweet nó cho những người theo dõi cho cuộc tranh luận Haskell / JVM tuyệt vời!
Martijn Verburg

6
@ m3th0dman: Scala có hỗ trợ chính xác cho các hàm bậc cao hơn như Java có. Trong Scala, các hàm hạng nhất được biểu diễn đơn giản dưới dạng các thể hiện của các lớp trừu tượng với một phương thức trừu tượng duy nhất, giống như Java. Chắc chắn, Scala có cú pháp cú pháp để xác định các hàm này và nó có một thư viện tiêu chuẩn phong phú về cả các loại hàm và phương thức được xác định trước chấp nhận các hàm, nhưng từ góc độ hệ thống , đó là câu hỏi này, không có gì khác biệt . Vì vậy, nếu Scala có thể làm điều đó, thì Java cũng có thể, và trên thực tế, có các thư viện FP lấy cảm hứng từ Haskell cho Java.
Jörg W Mittag

2
@ m3th0dman: Đó không phải là câu hỏi này.
Phil

7
@ m3th0dman Chúng là loại hoàn toàn bình thường. Không có gì đặc biệt về danh sách ngoại trừ một số chi tiết đồng bộ. Bạn có thể dễ dàng xác định loại dữ liệu đại số của riêng mình tương đương với loại danh sách tích hợp ngoại trừ cú pháp bằng chữ và tên của các hàm tạo.
sepp2k

Câu trả lời:


63

("Java", như được sử dụng ở đây, được định nghĩa là Java SE 7 tiêu chuẩn ; "Haskell", như được sử dụng ở đây, được định nghĩa là Haskell tiêu chuẩn 2010. )

Những thứ mà hệ thống kiểu Java có nhưng Haskell thì không:

  • đa hình danh nghĩa
  • thông tin loại thời gian chạy một phần

Những thứ mà hệ thống loại của Haskell có nhưng Java thì không:

  • đa hình ad-hoc giới hạn
    • làm phát sinh tính đa hình phụ "dựa trên ràng buộc"
  • đa hình tham số loại cao hơn
  • gõ chính

BIÊN TẬP:

Ví dụ về mỗi điểm được liệt kê ở trên:

Duy nhất với Java (so với Haskell)

Đa hình danh nghĩa

/* declare explicit subtypes (limited multiple inheritance is allowed) */
abstract class MyList extends AbstractList<String> implements RandomAccess {

    /* specify a type's additional initialization requirements */
    public MyList(elem1: String) {
        super() /* explicit call to a supertype's implementation */
        this.add(elem1) /* might be overridden in a subtype of this type */
    }

}

/* use a type as one of its supertypes (implicit upcasting) */
List<String> l = new ArrayList<>() /* some inference is available for generics */

Thông tin loại thời gian chạy một phần

/* find the outermost actual type of a value at runtime */
Class<?> c = l.getClass // will be 'java.util.ArrayList'

/* query the relationship between runtime and compile-time types */
Boolean b = l instanceOf MyList // will be 'false'

Duy nhất với Haskell (so với Java)

Đa hình ad-hoc

-- declare a parametrized bound
class A t where
  -- provide a function via this bound
  tInt :: t Int
  -- require other bounds within the functions provided by this bound
  mtInt :: Monad m => m (t Int)
  mtInt = return tInt -- define bound-provided functions via other bound-provided functions

-- fullfill a bound
instance A Maybe where
  tInt = Just 5
  mtInt = return Nothing -- override defaults

-- require exactly the bounds you need (ideally)
tString :: (Functor t, A t) => t String
tString = fmap show tInt -- use bounds that are implied by a concrete type (e.g., "Show Int")

Dạng đa hình phụ "dựa trên ràng buộc" (dựa trên đa hình ad-hoc bị ràng buộc)

-- declare that a bound implies other bounds (introduce a subbound)
class (A t, Applicative t) => B t where -- bounds don't have to provide functions

-- use multiple bounds (intersection types in the context, union types in the full type)
mtString :: (Monad m, B t) => m (t String)
mtString = return mtInt -- use a bound that is implied by another bound (implicit upcasting)

optString :: Maybe String
optString = join mtString -- full types are contravariant in their contexts

Đa hình tham số loại cao hơn

-- parametrize types over type variables that are themselves parametrized
data OneOrTwoTs t x = OneVariableT (t x) | TwoFixedTs (t Int) (t String)

-- bounds can be higher-kinded, too
class MonadStrip s where
  -- use arbitrarily nested higher-kinded type variables
  strip :: (Monad m, MonadTrans t) => s t m a -> t m a -> m a

Gõ chính

Đây là một ví dụ khó đưa ra một ví dụ trực tiếp, nhưng nó có nghĩa là mọi biểu thức đều có chính xác một loại tổng quát tối đa (được gọi là loại chính của nó ), được coi là loại chính tắc của biểu thức đó. Về mặt đa hình của kiểu con "dựa trên ràng buộc" (xem ở trên), kiểu chính của biểu thức là kiểu con duy nhất của mọi loại có thể mà biểu thức đó có thể được sử dụng như. Sự hiện diện của việc gõ chính trong Haskell (không được giám sát) là những gì cho phép suy luận kiểu hoàn chỉnh (nghĩa là suy luận kiểu thành công cho mọi biểu thức, mà không cần bất kỳ chú thích loại nào). Các phần mở rộng phá vỡ kiểu gõ chính (trong đó có nhiều phần) cũng phá vỡ tính hoàn chỉnh của suy luận kiểu.


7
Đừng sử dụng lnhư một biến chữ cái, rất khó để phân biệt 1!
đệ quy.ninja

5
Có thể đáng chú ý, mặc dù bạn hoàn toàn đúng khi Java có một số thông tin về kiểu thời gian chạy và Haskell thì không, bạn có thể sử dụng lớp loại có thể đánh máy trong Haskell để cung cấp thứ gì đó hoạt động như thông tin kiểu thời gian chạy cho nhiều loại (với PolyKinded mới hơn các lớp trên đường đi, nó sẽ là tất cả các loại iirc), mặc dù tôi nghĩ nó phụ thuộc vào tình huống liệu nó có thực sự vượt qua bất kỳ thông tin loại nào trong thời gian chạy hay không.

3
@DarkOtter Tôi biết Typeable, nhưng Haskell 2010 không có nó (có lẽ Haskell 2014 sẽ không?).
Ngọn lửa của Ptharien

5
Còn các loại tổng (đóng) thì sao? Chúng là một trong những cơ chế quan trọng hơn cho các ràng buộc mã hóa.
tibbe

3
Tính không ổn định? Âm thanh (không có sillinses hiệp phương sai)? Loại tổng đóng / mẫu phù hợp? Câu trả lời này quá hẹp
Peaker

32

Hệ thống kiểu Java thiếu tính đa hình loại cao hơn; Hệ thống loại của Haskell có nó.

Nói cách khác: trong Java, các hàm tạo kiểu có thể trừu tượng hóa các kiểu, nhưng không vượt quá các hàm tạo kiểu, trong khi ở Haskell, các hàm tạo kiểu có thể trừu tượng hơn các hàm tạo kiểu cũng như các kiểu.

Trong tiếng Anh: trong Java, một cái chung không thể lấy một loại chung khác và tham số hóa nó,

public void <Foo> nonsense(Foo<Integer> i, Foo<String> j)

trong khi ở Haskell thì việc này khá dễ

higherKinded :: Functor f => f Int -> f String
higherKinded = fmap show

28
Tâm trí điều đó bởi chúng ta một lần nữa, bằng tiếng Anh lần này? : P
Mason Wheeler

8
@Matt: Như một ví dụ tôi không thể viết điều này bằng Java, nhưng tôi có thể viết tương đương bằng Haskell : <T<_> extends Collection> T<Integer> convertStringsToInts(T<string> strings). Ý tưởng ở đây sẽ là nếu ai đó gọi nó vì convertStringsToInts<ArrayList>nó sẽ lấy một danh sách các chuỗi và trả về một danh sách các số nguyên. Và nếu thay vào đó chúng được sử dụng convertStringsToInts<LinkedList>, thì nó sẽ giống với danh sách được liên kết thay thế.
sepp2k

8
Đây không phải là đa hình loại cao hơn, chứ không phải xếp hạng 1 so với n?
Adam

8
@ JörgWMittag: Sự hiểu biết của tôi là sự đa hình cấp cao hơn mà bạn có thể đặt foralltrong các loại của mình. Trong Haskell, một loại a -> blà ngầm forall a. forall b. a -> b. Với một phần mở rộng, bạn có thể làm cho những cái này forallrõ ràng và di chuyển chúng xung quanh.
Tikhon Jelvis

8
@Adam là Rigtht: thứ hạng cao hơn và loại cao hơn là hoàn toàn khác nhau. GHC cũng có thể thực hiện các loại được xếp hạng cao hơn (ví dụ như các loại forall) với một số phần mở rộng ngôn ngữ. Java biết các loại không được xếp loại cao hơn hoặc cao hơn.
Ingo

11

Để bổ sung cho các câu trả lời khác, hệ thống loại của Haskell không có phân nhóm , trong khi gõ các ngôn ngữ hướng đối tượng như Java làm.

Trong lý thuyết ngôn ngữ lập trình , phân nhóm (cũng là đa hình phụ hoặc đa hình bao gồm ) là một dạng đa hình loại trong đó một kiểu con là một kiểu dữ liệu có liên quan đến một kiểu dữ liệu khác ( siêu kiểu ) bởi một số khái niệm về tính thay thế , nghĩa là các phần tử chương trình, điển hình là các phần tử chương trình hoặc các hàm, được viết để hoạt động trên các phần tử của siêu kiểu cũng có thể hoạt động trên các phần tử của kiểu con. Nếu S là một kiểu con của T, thì mối quan hệ phụ thường được viết S <: T, có nghĩa là bất kỳ thuật ngữ nào của loại S có thể được sử dụng một cách an toàn trong ngữ cảnhmột thuật ngữ loại T được dự kiến. Các ngữ nghĩa chính xác của việc phân nhóm chủ yếu phụ thuộc vào các chi tiết của "được sử dụng an toàn trong ngữ cảnh" nghĩa là gì trong một ngôn ngữ lập trình nhất định. Các hệ thống kiểu của một ngôn ngữ lập trình cơ bản xác định mối quan hệ subtyping riêng của mình, mà cũng có thể là tầm thường.

Do mối quan hệ phụ, một thuật ngữ có thể thuộc nhiều hơn một loại. Subtyping do đó là một dạng đa hình loại. Trong lập trình hướng đối tượng, thuật ngữ "đa hình" thường chỉ được sử dụng để chỉ đa hình phụ , trong khi các kỹ thuật của đa hình tham số sẽ được coi là lập trình chung ...


4
Mặc dù điều đó không có nghĩa là bạn không có được đa hình ad-hoc. Bạn làm, chỉ trong một hình thức khác (loại lớp thay vì đa hình phụ).

3
Phân lớp không phải là phân nhóm!
Frank Shearar

8

Một điều không ai nhắc đến cho đến nay là suy luận kiểu: trình biên dịch Haskell thường có thể suy ra kiểu biểu thức nhưng bạn phải nói với trình biên dịch Java các kiểu của bạn một cách chi tiết. Nghiêm túc, đây là một tính năng của trình biên dịch nhưng thiết kế của ngôn ngữ và hệ thống loại xác định xem suy luận kiểu có khả thi hay không. Cụ thể, kiểu suy luận tương tác xấu với đa hình phụ của Java và quá tải ad hoc. Ngược lại, các nhà thiết kế của Haskell cố gắng không giới thiệu các tính năng mà suy luận kiểu tác động.

Một điều khác mà mọi người dường như không đề cập cho đến nay là các loại dữ liệu đại số. Đó là, khả năng xây dựng các loại từ tổng ('hoặc') và sản phẩm ('và') của các loại khác. Các lớp Java làm các sản phẩm (trường a và trường b, nói) tốt. Nhưng họ không thực sự tính tổng (trường a OR trường b, nói). Scala phải mã hóa điều này thành nhiều lớp trường hợp, không hoàn toàn giống nhau. Và trong khi nó hoạt động cho Scala, có một chút khó khăn để nói Java có nó.

Haskell cũng có thể xây dựng các loại chức năng bằng cách sử dụng hàm tạo, ->. Trong khi các phương thức của Java có chữ ký loại, bạn không thể kết hợp chúng.

Hệ thống kiểu của Java cho phép một kiểu mô đun mà Haskell chưa có. Sẽ mất một lúc trước khi có OSGi cho Haskell.


1
@MattFenwick, tôi đã sửa đổi đoạn thứ 3 dựa trên phản hồi của bạn. Hai loại hệ thống xử lý các chức năng rất khác nhau.
GarethR

Tôi sẽ không gọi ADT là một tính năng của hệ thống loại. Bạn hoàn toàn có thể (nếu lúng túng) mô phỏng chúng bằng các hàm bao OO.
leftaroundabout

@leftaroundabout Tôi nghĩ điều này là có thể tranh cãi. Ví dụ, có thể có những thứ có nguồn gốc từ một hệ thống loại của một ngôn ngữ, nhưng có thể được triển khai với các mẫu thiết kế trong một ngôn ngữ khác. Rõ ràng, cách thiết kế mẫu, so với bản địa, là một cách giải quyết. Cách giải quyết do hệ thống loại yếu hơn.
Hi-Angel

Câu trả lời được chọn đề cập đến 'suy luận kiểu hoàn chỉnh' trong phần 'Gõ chính'. Java có thể sắp xếp các khoản tiền giả lập với các kiểu con và thông tin loại thời gian chạy, nhưng như bạn nói, nó không giống như tổng không phải là một thuộc tính tổng thể của hệ thống loại.
Shelby Moore III
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.