热衷于阅读以了解Haskell为您带来的好处!并且在理解实例和种类方面遇到很大麻烦。
Q1:那么t
中的类型Tofu t
充当具有类型签名(* -> (* -> *)) -> *
的函数吗? tofu
的整体种类签名为* -> *
,不是吗?因为(* -> *) -> *
的结果是*
,(* -> (* -> *)) -> *
的结果也是
第二季度:当我们要创建类型为Frank a b
的{{1}}实例时,数据类型Tofu t
也必须与Frank a b
具有相同的种类。这意味着t
的种类为a
,*
的种类为b
,而* -> *
的种类为b a
,结果为(* -> *) -> *
。正确吗?
Q3:*
中的x
代表tofu x
,因为两者都具有j a
的类型。 *
及其种类Frank
应用于(* -> (* -> *)) -> *
。但是我不确定将x
表示为j a
会如何区分x
中的x
中的tofu x
和{{ 1}},即j a
。
我对在数据类型或类(例如:x
中的Frank x
或a j
中的b
)内部具有函数的想法很陌生有点混乱
我在此保留链接,因为引用会使帖子看起来不必要地冗长。 link
Frank a b
答案 0 :(得分:5)
第一季度:
因此,豆腐t中的类型t充当具有类型签名(*->(*-> *))-> *?
的函数
t
的种类是* -> (* -> *) -> *
,或更明确地说是* -> ((* -> *) -> *)
,而不是(* -> (* -> *)) -> *
。
豆腐的整体特征是*-> *,不是吗?
tofu
没有类型签名,只有类型构造函数有。其类型为*
。它的参数和结果的类型也是如此。而且对于任何功能都一样。
Q2:您从一个错误的假设开始:instance Tofu Frank
使Frank
类型的构造函数成为Tofu
而不是Frank a b
的实例。因此,Frank
的类型必须与t
相同,而不是Frank a b
(其类型为*
)。
b a将会是(*-> *)-> *
否,b a
是b
类型的* -> *
到a
类型的*
的应用程序,因此该应用程序是*
类型的应用程序。就像b
是类型x -> y
的函数,而a
是类型x
的值一样,b a
的类型为y
,不是(x -> y) -> x
:只需将x
和y
替换为*
。
第三季度:
豆腐x中的x代表j a
“具有类型”,而不是“代表”。
因为两者都有*
x
没有种类,因为它不是种类。
以实物类型(*->(*-> *))-> *应用于x
不,在
tofu x = Frank x
是Frank
的{{1}} data constructor,而不是类型构造函数。这是一个带有签名x
的函数(将b a1 -> Frank a1 b
重命名为a
的函数)。所以tofu
和b ~ j
。
答案 1 :(得分:2)
Alexey已经可以回答您的问题了。取而代之的是,我将在您的示例中详细说明所有相关的细节。
class Tofu t where
tofu :: j a -> t a j
^^^ ^^^^^
^^^^^^^^^^^^
突出显示的位必须具有种类*
。 (类型级别)箭头两侧的任何内容都必须具有类型*
[1] ,并且箭头术语本身(即整个j a -> t a j
术语)也具有类型*
。实际上,可以被值占用的任何“类型” [2] 都具有类型*
。如果它有其他任何一种,就没有任何值(它只是用来在别处构造适当的类型)。
因此,在tofu
的签名中,以下内容成立
j a :: *
t a j :: *
因为它们是(->)
的参数,所以被用作“有人居住”类型。
这是限制类的唯一因素。特别地,a
可以是任何种类。使用PolyKinds
[3]
a :: k -- for any kind k
j :: k -> *
t :: k -> (k -> *) -> *
^ ^^^^^^^^ ^
kind of a kind of j required since is used as inhabited type by ->
因此,我们找到了所需的t
类型。
我们可以对Frank
使用类似的推理。
data Frank a b = Frank {frankField :: b a}
^^^^^^^^^ ^^^
同样,突出显示的位必须具有种类*
,因为它们可以具有值。否则没有约束。概括地说,我们有
a :: k
b :: k -> *
Frank a b :: *
因此
Frank :: k -> (k -> *) -> *
我们可以看到Frank
的种类与Tofu
所需的种类匹配。但这对于更具体的种类也很有意义,例如:
data KatyPerry a b = KatyPerry a (b Int)
尝试推断她的种类,并检查它是否比Tofu
要求的种类更具体。
[1]如果我们假设TypeInType
,则在种类级别的箭头上也是如此。没有TypeInType
,“种类”称为 sorts ,没有人担心它们。通常在该级别上没有发生任何有趣的事情。
[2]我将“类型”用引号引起来,因为从技术上讲,只有类型为*
的东西才称为类型,其他所有东西都称为类型构造函数。我试图做到这一点很精确,但是我找不到一次同时引用两者的非笨拙方式,因此该段变得非常混乱。所以是“类型”。
[3]如果没有PolyKinds
,则诸如k
这样不受约束的任何事物都将专用于*
。这也意味着Tofu
的类型可能取决于您首先在哪种类型上对其进行实例化,或者是在同一模块中还是在不同模块中将其实例化。这不好。 PolyKinds
很好。