Sự khác biệt giữa một loại và một loại là gì?


26

Tôi đang học ngôn ngữ lập trình Haskell, và tôi đang cố gắng che giấu sự khác biệt giữa a typevà a kindlà gì.

Theo tôi hiểu , a kind is a type of type. Ví dụ, a ford is a type of cara car is a kind of vehicle.

Đây có phải là một cách tốt để suy nghĩ về điều này?

Bởi vì, cách mà bộ não của tôi hiện đang có dây, a ford is a **type** of car, nhưng cũng là một car is a **type** of vehiclelúc trong khi a car is a **kind** of vehicle. Tức là các điều khoản typekindcó thể thay thế cho nhau.

Bất cứ ai có thể làm sáng tỏ về điều này?


6
Tôi vừa đến đây từ bài đăng trên Stack Overflow dẫn đến cuộc thảo luận này. Tôi không chắc chắn mình đủ điều kiện để trả lời chi tiết - nhưng bạn chắc chắn quá hiểu về các thuật ngữ "loại" và "loại", khi cố gắng liên hệ chúng với nghĩa của chúng trong tiếng Anh (trong đó thực sự chúng là từ đồng nghĩa ). Bạn nên coi chúng là thuật ngữ kỹ thuật. "Loại" được tất cả các lập trình viên hiểu rõ, bởi vì khái niệm này rất quan trọng đối với mọi ngôn ngữ, ngay cả những ngôn ngữ được đánh máy yếu như Javascript, "Loại" là một thuật ngữ kỹ thuật được sử dụng trong Haskell cho "loại của một loại". Đó thực sự là tất cả để có nó.
Robin Zigmond

2
@RobinZigmond: bạn nói đúng rằng đây là những thuật ngữ kỹ thuật, nhưng chúng được sử dụng rộng rãi hơn là chỉ trong Haskell. Có lẽ backlink đến cuộc thảo luận Stack Overflow bắt đầu câu hỏi này?
Andrej Bauer

@AndrejBauer Tôi chưa bao giờ nói rằng họ không được sử dụng bên ngoài Haskell, chắc chắn "loại" được sử dụng trong tất cả các ngôn ngữ, như tôi đã nói. Tôi chưa bao giờ thực sự bắt gặp "loại" bên ngoài Haskell, nhưng sau đó Haskell là ngôn ngữ chức năng duy nhất tôi biết, và tôi cẩn thận không nói thuật ngữ này không được sử dụng ở nơi khác, chỉ là nó được sử dụng theo cách đó trong Haskell. (Và liên kết, như bạn yêu cầu, có ở đây )
Robin Zigmond

Các ngôn ngữ gia đình ML cũng có các loại, ví dụ Standard ML và OCaml. Họ nghĩ rằng họ không bị lộ rõ ​​ràng bởi cái tên đó. Chúng được biểu hiện dưới dạng chữ ký và các yếu tố của chúng được gọi là cấu trúc .
Andrej Bauer

1
Một từ tương tự tiếng Anh chính xác hơn là Ford là một loại xe hơi và xe hơi là một loại phương tiện nhưng cả loại xe và loại xe đều cùng loại: danh từ. Trong khi đó màu đỏ là một loại màu xe hơi và RPM là một loại số liệu hiệu suất xe hơi và cả hai đều cùng loại: tính từ.
slebetman

Câu trả lời:


32

Ở đây, "giá trị", "loại" và "loại" có ý nghĩa chính thức, vì vậy việc xem xét cách sử dụng tiếng Anh phổ biến hoặc tương tự để phân loại ô tô sẽ chỉ đưa bạn đến nay.

Câu trả lời của tôi liên quan đến ý nghĩa chính thức của các thuật ngữ này trong bối cảnh của Haskell cụ thể; những ý nghĩa này dựa trên (mặc dù không thực sự giống với) những ý nghĩa được sử dụng trong "lý thuyết loại" toán học / CS. Vì vậy, đây sẽ không phải là một câu trả lời "khoa học máy tính" rất tốt, nhưng nó sẽ đóng vai trò là một câu trả lời khá hay của Haskell.

Trong Haskell (và các ngôn ngữ khác), việc gán một loại cho biểu thức chương trình mô tả lớp giá trị mà biểu thức được phép có là điều hữu ích . Tôi giả sử ở đây rằng bạn đã thấy đủ các ví dụ để hiểu lý do tại sao sẽ hữu ích khi biết rằng trong biểu thức sqrt (a**2 + b**2), các biến absẽ luôn là các giá trị của kiểu Doublevà không, nói, StringBooltương ứng. Về cơ bản, có các loại hỗ trợ chúng ta viết các biểu thức / chương trình sẽ hoạt động chính xác trên một loạt các giá trị .

Bây giờ, một điều bạn có thể không nhận ra là các loại Haskell, giống như các loại xuất hiện trong chữ ký loại:

fmap :: Functor f => (a -> b) -> f a -> f b

thực ra chính chúng được viết bằng một ngôn ngữ con Haskell cấp độ loại. Văn bản chương trình Functor f => (a -> b) -> f a -> f blà - hoàn toàn theo nghĩa đen - một biểu thức kiểu được viết bằng ngôn ngữ con này. Các sublanguage bao gồm các nhà khai thác (ví dụ, ->là một nhà điều hành ghi kết hợp ngay trong ngôn ngữ này), các biến (ví dụ f, ab), và "ứng dụng" của một biểu thức kiểu khác (ví dụ, f ađược fáp dụng cho a).

Tôi đã đề cập đến việc làm thế nào hữu ích trong nhiều ngôn ngữ để gán các loại cho các biểu thức chương trình để mô tả các lớp của các giá trị biểu thức? Vâng, trong ngôn ngữ con cấp độ loại này, các biểu thức đánh giá các loại (chứ không phải giá trị ) và cuối cùng sẽ hữu ích khi gán các loại cho biểu thức loại để mô tả các loại loại mà chúng được phép đại diện. Về cơ bản, có các loại hỗ trợ chúng ta bằng cách viết các biểu thức loại sẽ hoạt động chính xác trên một loạt các loại .

Vì vậy, các giá trịloại như loạiloạiloại giúp chúng ta viết chương trình giá trị -level trong khi loại giúp chúng ta viết chương trình loại -level.

Những loại này trông như thế nào? Vâng, hãy xem xét chữ ký loại:

id :: a -> a

Nếu biểu thức loại a -> alà có giá trị, những gì loại của các loại chúng ta nên cho phép biến ađược? Vâng, các biểu thức loại:

Int -> Int
Bool -> Bool

Nhìn hợp lệ, vì vậy các loại IntBoolrõ ràng là đúng loại . Nhưng thậm chí các loại phức tạp hơn như:

[Double] -> [Double]
Maybe [(Double,Int)] -> Maybe [(Double,Int)]

nhìn hợp lệ Trong thực tế, vì chúng ta phải có khả năng gọi các idchức năng, thậm chí:

(a -> a) -> (a -> a)

nhìn ổn. Vì vậy, Int, Bool, [Double], Maybe [(Double,Int)], và a -> atất cả nhìn như loại quyền loại .

Nói cách khác, có vẻ như chỉ có một loại , hãy gọi nó *giống như một ký tự đại diện Unix và mọi loại đều có cùng một loại * , kết thúc câu chuyện.

Đúng?

Vâng, không hoàn toàn. Nó chỉ ra rằng Maybe, tất cả chính nó, chỉ là một biểu thức kiểu hợp lệ Maybe Int(theo nhiều cách giống nhau sqrt, tất cả đều giống như một biểu thức giá trị như sqrt 25). Tuy nhiên , biểu thức loại sau không hợp lệ:

Maybe -> Maybe

Bởi vì, trong khi Maybelà một biểu thức kiểu, nó không đại diện cho loại của loại đó có thể có giá trị. Vì vậy, đó là cách chúng ta nên xác định *- đó là loại của các loại có giá trị; nó bao gồm các loại "hoàn thành" như Doublehoặc Maybe [(Double,Int)]nhưng loại trừ các loại không hoàn chỉnh, không có giá trị như Either String. Để đơn giản, tôi sẽ gọi những loại hoàn chỉnh này là *" loại cụ thể", mặc dù thuật ngữ này không phổ biến và "loại cụ thể" có thể có nghĩa gì đó rất khác với một lập trình viên C ++.

Bây giờ, trong biểu thức kiểu a -> a, miễn là loại aloại * (loại bê tông), kết quả của biểu thức loại cũnga -> a sẽ có loại (nghĩa là loại bê tông). *

Vì vậy, những gì loại của loạiMaybe? Vâng, Maybecó thể được áp dụng cho một loại bê tông để mang lại một loại bê tông khác. Vì vậy, Maybetrông giống như một chút giống như một loại chức năng cấp mà phải mất một kiểu của loại * và trả về một kiểu của loại * . Nếu chúng ta có hàm mức giá trị lấy giá trị của loại Int và trả về giá trị của loại Int , chúng ta sẽ cung cấp cho nó một chữ ký loạiInt -> Int , do đó, bằng cách tương tự, chúng ta nên đưa ra Maybemột chữ ký loại* -> * . GHCi đồng ý:

> :kind Maybe
Maybe :: * -> *

Sẽ trở lại:

fmap :: Functor f => (a -> b) -> f a -> f b

Trong loại chữ ký này, biến fcó loại * -> *và biến abcó loại *; toán tử tích hợp ->có loại * -> * -> *(nó lấy một loại *ở bên trái và một ở bên phải và trả về một loại cũng có loại *). Từ điều này và các quy tắc suy luận loại, bạn có thể suy ra đó a -> blà một loại hợp lệ với loại *, f af bcũng là loại hợp lệ với loại *, và (a -> b) -> f a -> f blà loại hợp lệ *.

Nói cách khác, trình biên dịch có thể "kiểm tra loại" biểu thức loại (a -> b) -> f a -> f bđể xác minh nó hợp lệ cho các biến loại đúng loại giống như cách "kiểm tra kiểu" sqrt (a**2 + b**2)để xác minh nó hợp lệ cho các biến đúng loại.

Lý do sử dụng các thuật ngữ riêng cho "loại" so với "loại" (nghĩa là không nói về "loại loại") chủ yếu chỉ để tránh nhầm lẫn. Các loại ở trên trông rất khác với các loại và, ít nhất là lúc đầu, dường như cư xử khá khác nhau. (Ví dụ, phải mất một thời gian để quấn quanh đầu của bạn xung quanh ý tưởng rằng mỗi "bình thường" loại có cùng loại *và các loại a -> b*không * -> *.)

Một số điều này cũng là lịch sử. Khi GHC Haskell đã phát triển, sự khác biệt giữa các giá trị, loại và loại đã bắt đầu mờ đi. Ngày nay, các giá trị có thể được "quảng bá" thành các loại, và các loại và các loại thực sự giống nhau. Vì vậy, trong Haskell hiện đại, giá trị cả hai đều có chủng loại và loại (hầu như), và các loại định dạng nhiều loại chỉ hơn.

@ user21820 yêu cầu một số giải thích bổ sung về "các loại và loại thực sự giống nhau". Nói rõ hơn một chút, trong GHC Haskell hiện đại (kể từ phiên bản 8.0.1, tôi nghĩ), các loại và loại được xử lý thống nhất trong hầu hết các mã trình biên dịch. Trình biên dịch thực hiện một số nỗ lực trong các thông báo lỗi để phân biệt giữa "loại" và "loại", tùy thuộc vào việc nó phàn nàn về loại giá trị hoặc loại tương ứng.

Ngoài ra, nếu không có tiện ích mở rộng nào được bật, chúng có thể dễ dàng phân biệt bằng ngôn ngữ bề mặt. Ví dụ: các loại (của các giá trị) có một biểu diễn trong cú pháp (ví dụ: trong các chữ ký loại), nhưng các loại (các loại) là - tôi nghĩ - hoàn toàn ẩn và không có cú pháp rõ ràng nơi chúng xuất hiện.

Nhưng, nếu bạn bật các tiện ích mở rộng phù hợp, sự khác biệt giữa các loại và phần lớn sẽ biến mất. Ví dụ:

{-# LANGUAGE GADTs, TypeInType #-}
data Foo where
  Bar :: Bool -> * -> Foo

Ở đây, Barlà (cả một giá trị và) một loại. Là một loại, loại của nó Bool -> * -> Foo, là một hàm cấp loại có một loại Bool(là một loại, nhưng cũng là một loại) và một loại *và tạo ra một loại Foo. Vì thế:

type MyBar = Bar True Int

kiểm tra loại chính xác.

Như @AndrejBauer giải thích trong câu trả lời của mình, việc không phân biệt được loại và loại này là không an toàn - có một loại / loại *có loại / loại chính nó (đó là trường hợp của Haskell hiện đại) dẫn đến nghịch lý. Tuy nhiên, hệ thống loại của Haskell đã đầy những nghịch lý vì không chấm dứt, vì vậy nó không được coi là một vấn đề lớn.


Nếu "các loại và các loại thực sự giống nhau", thì loại typechỉ là typechính nó, và sẽ không có nhu cầu nào cả kind. Vậy chính xác sự khác biệt là gì?
user21820

1
@ user21820, tôi đã thêm một ghi chú vào cuối có thể giải quyết vấn đề này. Câu trả lời ngắn: thực sự không có sự khác biệt trong GHC Haskell hiện đại .
KA Buhr

1
Đây là một câu trả lời tuyệt vời - cảm ơn rất nhiều vì đã chia sẻ. Nó được viết tốt và giới thiệu các khái niệm dần dần - như một người đã không viết Haskell trong một vài năm, điều này rất được đánh giá cao!
ultrafez

@KABuhr: Cảm ơn vì đã thêm bit!
user21820

19

type:ktôind= =Set:ctôimộtSS.

  • Bool là một loại
  • Type là một loại vì các yếu tố của nó là các loại
  • Bool -> Int là một loại
  • Bool -> Type là một loại vì các phần tử của nó là các hàm trả về các kiểu
  • Bool * Int là một loại
  • Bool * Type là một loại vì các phần tử của nó là các cặp với một thành phần một loại

Bạn0Bạn1Bạn2Bạn0BootôiNmộttNmộttNmộttBạn1Bạn0BootôiBạn0Bạn0Bạn0Bạnn+1BạnnBạnn×

Bạn0Bạn1Bạn0Bạn1Bạn0**U_1


2
Tôi không nghĩ (GHC) Haskell có bất kỳ khái niệm nào về vũ trụ. Type :: Typelà một tiên đề. Sự khác biệt giữa "loại" và "loại" hoàn toàn bằng ngôn ngữ của con người, trong trường hợp đó. Truecó một loại, BoolBoolcó một loại Type, bản thân nó có loại Type. Đôi khi chúng ta gọi một loại là một loại, để nhấn mạnh rằng đó là loại thực thể cấp loại, nhưng, trong Haskell, nó vẫn chỉ là một loại. Trong một hệ thống nơi các vũ trụ thực sự tồn tại, như Coq, thì "loại" có thể đề cập đến một vũ trụ và "loại" cho một vũ trụ khác, nhưng sau đó chúng ta thường muốn vô số vũ trụ.
HTNW

1
Sự khác biệt không chỉ là "ngôn ngữ của con người", đó là sự khác biệt chính thức trong hệ thống loại cơ bản. Hoàn toàn có thể có cả hai Type :: Typevà sự khác biệt giữa các loại và loại. Ngoài ra, đoạn mã nào thể hiện Type :: Typetrong Haskell?
Andrej Bauer

1
Tôi cũng nên nói rằng *trong Haskell là một vũ trụ. Họ không gọi nó như vậy.
Andrej Bauer

3
@AndrejBauer Typetừ Data.Kinds*nên là từ đồng nghĩa. Ban đầu chúng tôi chỉ có *một nguyên thủy, trong khi ngày nay được xác định bên trong như GHC.Types.Typetrong mô-đun bên trong GHC.Types, lần lượt được định nghĩa là type Type = TYPE LiftedRep. Tôi nghĩ TYPElà người nguyên thủy thực sự, cung cấp một họ các loại (loại nâng, loại không có hộp, ...). Hầu hết sự phức tạp "không phù hợp" ở đây là để hỗ trợ một số tối ưu hóa ở mức độ thấp, và không phải vì lý do lý thuyết loại thực tế.
chi

1
Tôi sẽ cố gắng tóm tắt. Nếu vlà một giá trị, thì nó có một loại : v :: T. Nếu Tlà một loại, thì nó có một loại : T :: K. Loại của loại được gọi là loại của nó. Các loại trông giống như TYPE repcó thể được gọi là sắp xếp, mặc dù từ này không phổ biến. Iff T :: TYPE repđược Tphép xuất hiện trên RHS của a ::. Từ "loại" có sắc thái với nó: Ktrong T :: Klà một loại, nhưng không phải trong v :: K, mặc dù nó giống nhau K. Chúng ta có thể định nghĩa " Klà một loại nếu loại đó là loại" aka "nằm trong RHS của ::", nhưng điều đó không nắm bắt được cách sử dụng một cách chính xác. Do đó, vị trí "phân biệt con người" của tôi.
HTNW

5

Một giá trị giống như các cụ đỏ 2011 Ford Mustang với 19.206 dặm trên đó mà bạn đã ngồi trong đường lái xe của bạn.

Giá trị cụ thể đó, không chính thức, có thể có nhiều loại : đó là Mustang, và đó là Ford, và là xe hơi, và nó là một phương tiện, trong số nhiều loại khác mà bạn có thể tạo nên (loại "thứ" thuộc về bạn "hoặc loại" những thứ màu đỏ "hoặc ...).

(Trong Haskell, với xấp xỉ thứ tự đầu tiên (GADT phá vỡ thuộc tính này và phép thuật xung quanh chữ số và phần mở rộng OverloadedStrings che khuất nó một chút), các giá trị có một loại chính thay vì vô số loại "không chính thức" mà bạn có thể cung cấp cho ' stang. 42là, cho mục đích của lời giải thích này, một Int, không có loại nào trong Haskell cho "số" hoặc "số nguyên", thay vào đó, bạn có thể tạo một loại, nhưng nó sẽ là một loại rời rạc từ Int.)

Bây giờ, "Mustang" có thể là một kiểu con của giá trị "xe hơi", một chiếc Mustang cũng là một chiếc xe hơi. Nhưng loại hay, để sử dụng thuật ngữ của Haskell, loại "Mustang" không phải là "xe hơi". "Mustang" loại không phải là thứ bạn có thể đỗ trên đường lái xe hoặc lái xe vòng quanh. "Mustang" là một danh từ, hoặc một danh mục, hoặc chỉ là một loại. Đó là, không chính thức, các loại "Mustang".

(Một lần nữa, Haskell chỉ nhận ra một loại cho mỗi loại cấp độ. Vì vậy, Intcó loại *, và không có loại nào khác. MaybeCó loại * -> *, và không có loại nào khác. Nhưng trực giác vẫn nên giữ: 42là một Int, và bạn có thể làm Intmọi thứ với nó giống như cộng và trừ. IntBản thân nó không phải là một Intsố không có Int + Int. Như vậy, bạn có thể nghe một cách không chính thức mọi người nói rằng đó Intlà một Num, theo đó họ có nghĩa là có một thể hiện của Numlớp loại cho loại Intđiều đó không giống nhau như nói rằng Intloại Num . Intcó loại "loại", trong Haskell được đánh vần *.)

Vì vậy, không phải mọi "loại" không chính thức chỉ là một danh từ hoặc một danh mục? Có phải tất cả các loại có cùng loại? Tại sao lại nói về các loại nếu chúng quá nhàm chán?

Đây là nơi tương tự tiếng Anh sẽ có một chút đanh đá, nhưng hãy đồng ý với tôi: giả vờ rằng từ "chủ sở hữu" trong tiếng Anh không có nghĩa gì trong sự cô lập, không có mô tả về thứ được sở hữu. Giả vờ rằng nếu ai đó gọi bạn là "chủ sở hữu", điều đó sẽ không có ý nghĩa gì với bạn cả; nhưng nếu ai đó gọi bạn là "chủ xe", bạn có thể hiểu ý của họ.

"Chủ sở hữu" không có cùng loại với "xe hơi", bởi vì bạn có thể nói về một chiếc xe hơi, nhưng bạn không thể nói về chủ sở hữu trong phiên bản tiếng Anh trang điểm này. Bạn chỉ có thể nói về một "chủ xe". "Chủ sở hữu" chỉ tạo ra một cái gì đó thuộc "danh từ" khi nó được áp dụng cho một cái gì đó đã có "danh từ", như "xe hơi". Chúng ta sẽ nói rằng loại "chủ sở hữu" là "danh từ -> danh từ". "Chủ sở hữu" giống như một chức năng lấy một danh từ và tạo ra từ đó một danh từ khác; nhưng bản thân nó không phải là danh từ

Lưu ý rằng "chủ xe" không phải là một kiểu con của "xe hơi"! Đây không phải là một chức năng chấp nhận hoặc trả lại xe ô tô! Nó chỉ là một loại hoàn toàn tách biệt với "xe hơi". Nó mô tả các giá trị với hai cánh tay và hai chân tại một thời điểm có một số tiền nhất định và đã mang số tiền đó đến một đại lý. Nó không mô tả các giá trị có bốn bánh xe và công việc sơn. Cũng lưu ý rằng "chủ xe" và "chủ chó" là những loại khác nhau và những điều bạn có thể muốn làm với loại này có thể không áp dụng cho loại kia.

(Tương tự như vậy, khi chúng ta nói điều đó Maybetốt * -> *với Haskell, chúng ta có nghĩa là nó vô lý (chính thức; chúng ta làm điều đó mọi lúc) để nói về việc có "a Maybe". Thay vào đó, chúng ta có thể có một Maybe Inthoặc Maybe Stringvì, đó là những điều của tử tế *.)

Vì vậy, toàn bộ vấn đề nói về các loại là để chúng ta có thể chính thức hóa lý lẽ của mình xung quanh các từ như "chủ sở hữu" và thực thi rằng chúng ta chỉ lấy các giá trị của các loại đã được "xây dựng đầy đủ" và không vô nghĩa.


1
Tôi không nói rằng sự tương tự của bạn là sai, nhưng tôi nghĩ nó có thể gây nhầm lẫn. Dijkstra có một số từ về tương tự. Google "Về sự tàn khốc của việc thực sự giảng dạy khoa học máy tính".
Rafael Castro

Ý tôi là, có những chiếc xe tương tự, và sau đó có những chiếc xe tương tự. Tôi không nghĩ rằng làm nổi bật cấu trúc kiểu ngầm trong một ngôn ngữ tự nhiên (mà, phải thừa nhận rằng tôi đã kéo dài trong nửa sau) như một cách giải thích một hệ thống loại chính thức giống như cách nói tương tự như dạy học những gì một chương trình "muốn" làm.
dùng11228628

1

Theo tôi hiểu, một loại là một loại.

Điều đó đúng - vì vậy hãy khám phá điều đó có nghĩa là gì. Inthoặc Textlà các loại cụ thể, nhưng Maybe alà một loại trừu tượng . Nó sẽ không trở thành một loại cụ thể cho đến khi bạn quyết định giá trị cụ thể nào bạn muốn acho một biến cụ thể (hoặc giá trị / biểu thức / bất cứ điều gì), vd Maybe Text.

Chúng tôi nói rằng đó Maybe alà một hàm tạo kiểu vì nó giống như một hàm lấy một loại bê tông duy nhất (ví dụ Text) và trả về một loại bê tông ( Maybe Texttrong trường hợp này). Nhưng các hàm tạo kiểu khác có thể mất nhiều "tham số đầu vào" hơn trước khi chúng trả về một kiểu cụ thể. ví dụ: Map k vcần lấy hai loại bê tông (ví dụ IntText) trước khi có thể xây dựng một loại bê tông ( Map Int Text).

Vì vậy, các hàm tạo Maybe aList akiểu có cùng một "chữ ký" mà chúng ta biểu thị là * -> *(tương tự chữ ký hàm Haskell) bởi vì nếu bạn cung cấp cho chúng một loại bê tông, chúng sẽ phun ra một loại cụ thể. Chúng tôi gọi đây là "loại" của loại MaybeListcó cùng loại.

Các loại bê tông được cho là có loại *và ví dụ Bản đồ của chúng tôi là loại * -> * -> *vì nó lấy hai loại bê tông làm đầu vào trước khi nó có thể xuất ra một loại bê tông.

Bạn có thể nhìn thấy nó là chủ yếu chỉ là về số lượng "thông số" mà chúng ta vượt qua vào constructor loại - nhưng nhận ra rằng chúng ta có thể cũng bị loại nhà xây dựng lồng vào bên trong loại nhà thầu, vì vậy chúng tôi có thể kết thúc với một loại mà trông giống như * -> (* -> *) -> *ví dụ .

Nếu bạn là nhà phát triển Scala / Java, bạn cũng có thể thấy giải thích này hữu ích: https://www.atlassian.com/blog/archives/scala-types-of-a-higher-kind


Điều này LAF không đúng. Trong Haskell, chúng tôi phân biệt giữa Maybe a, một từ đồng nghĩa cho forall a. Maybe a, một loại đa hình *Maybemột loại đơn hình * -> *.
b0fh
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.