[英]Understanding signature of data type, typeclass, and making a data type an instance of a typeclass
Been reading Learn You A Haskell For a Great Good ! 正在阅读学习Haskell为您带来伟大的成就! and have big trouble with understanding instance and kind.
并且在理解实例和种类方面遇到了很大的麻烦。
Q1: So the type t
in Tofu t
acts as a function with the kind signature (* -> (* -> *)) -> *
? 问题1:因此,
Tofu t
的类型t
充当具有类型签名(* -> (* -> *)) -> *
的函数? And the overall kind signature of tofu
is * -> *
, isnt it? tofu
的整体特征是* -> *
,不是吗? since (* -> *) -> *
results in *
and so does (* -> (* -> *)) -> *
因为
(* -> *) -> *
导致*
, (* -> (* -> *)) -> *
Q2: When we want to make Frank ab
instance of the typeclass Tofu t
, data type Frank ab
must also have the same kind with t
. Q2:当我们要使
Tofu t
类型类的Frank ab
实例时,数据类型Frank ab
也必须与t
具有相同的种类。 That means kind of a
is *
, b
is * -> *
, and ba
which will be (* -> *) -> *
which results in *
. 这意味着种
a
是*
, b
是* -> *
,和ba
这将是(* -> *) -> *
这导致*
。 Is that correct? 那是对的吗?
Q3: The x
in tofu x
represents ja
since both have the kind of *
. Q3:在
x
在tofu x
代表ja
因为两者具有的那种*
。 Frank
with its kind (* -> (* -> *)) -> *
is applied on x
. 种类为
(* -> (* -> *)) -> *
Frank
应用于x
。 But I'm not sure how presenting ja
as x
will distinguish the x
in tofu x
which is ja
and the x
in Frank x
which is aj
. 但我不知道如何呈现
ja
为x
将区分x
在tofu x
是ja
和x
在Frank x
是aj
。
I'm kind of new to the idea of having a function inside data type or class (Ex: b
in Frank ab
or t
in Tofu t
) which is a bit confusing 我种新的具有数据类型或类的内部的功能的想法(例如:
b
在Frank ab
或t
在Tofu t
),这是有点混乱
I leave the link here since quoting would make the post look unnecessarily long. 我将链接留在这里,因为引用会使帖子看起来不必要地冗长。 link
链接
class Tofu t where
tofu :: j a -> t a j
data Frank a b = Frank {frankField :: b a}
instance Tofu Frank where
tofu x = Frank x
Q1: Q1:
So the type t in Tofu t acts as a function with the kind signature (* -> (* -> *)) -> * ?
因此,豆腐t中的类型t充当具有类型签名(*->(*-> *))-> *的函数?
t
's kind is * -> (* -> *) -> *
, or more explicitly * -> ((* -> *) -> *)
, not (* -> (* -> *)) -> *
. t
的种类是* -> (* -> *) -> *
或更明确地* -> ((* -> *) -> *)
而不是(* -> (* -> *)) -> *
。
And the overall kind signature of tofu is * -> *, isnt it?
豆腐的整体特征是*-> *,不是吗?
tofu
doesn't have a kind signature, only type constructors do; tofu
没有种类签名,只有类型构造函数有。 its type's kind is *
. 其类型为
*
。 So are its argument's and result's types. 它的参数和结果的类型也是如此。 And same for any function.
并且对于任何功能都相同。
Q2: You start with a wrong supposition: instance Tofu Frank
makes the Frank
type constructor an instance of Tofu
, not Frank ab
. Q2:您从一个错误的假设开始:
instance Tofu Frank
使Frank
类型构造函数成为Tofu
的实例,而不是Frank ab
的实例。 So it's Frank
which must have the same kind as t
, not Frank ab
(which has kind *
). 所以这是
Frank
必须具有相同种类t
,不Frank ab
(其中有一种*
)。
ba which will be (* -> *) -> *
ba将是(*-> *)-> *
No, ba
is an application of b
of kind * -> *
to a
of kind *
, so the application has kind *
. 不,
ba
是一个应用b
样的* -> *
给a
样*
,因此应用程序有种*
。 Exactly as if b
was a function of type x -> y
, and a
was a value of type x
, ba
would have type y
, not (x -> y) -> x
: just replace x
and y
by *
. 就像
b
是x -> y
类型的函数,而a
是x
类型的值一样, ba
的类型将是y
,而不是(x -> y) -> x
:仅用*
替换x
和y
。
Q3: 第三季度:
The x in tofu x represents ja
豆腐x中的x代表ja
"Has type", not "represents". “具有类型”,而不是“代表”。
since both have the kind of *
因为两者都有*
x
doesn't have a kind, because it isn't a type. x
没有种类,因为它不是种类。
Frank with its kind (* -> (* -> *)) -> * is applied on x
带有类型(*->(*-> *))-> *的Frank应用于x
No, in 不,在
tofu x = Frank x
it's the Frank
data constructor which is applied to x
, not the type constructor. 是应用于
x
的Frank
数据构造 x
,而不是类型构造函数。 It's a function with signature b a1 -> Frank a1 b
(renaming a
so you don't confuse it with tofu
's). 这是一个具有签名
b a1 -> Frank a1 b
的函数(重命名a
这样就不会与tofu
混淆了)。 So b ~ j
and a1 ~ a
. 所以
b ~ j
和a1 ~ a
。
Alexey already had a go at answering your questions. Alexey已经可以回答您的问题了。 I'll instead expound on your example with whatever details seem relevant.
相反,我将用任何看起来相关的细节来说明您的示例。
class Tofu t where
tofu :: j a -> t a j
^^^ ^^^^^
^^^^^^^^^^^^
The highlighted bits must have kind *
. 突出显示的位必须为
*
。 Anything on either side of a (type level) arrow must have type *
[1] , and the arrow term itself (that is, the whole ja -> taj
term) also has kind *
. (类型级别)箭头两侧的任何内容都必须具有类型
*
[1] ,并且箭头术语本身(即整个ja -> taj
术语)也具有类型*
。 Indeed, any "type" [2] that can be inhabited by a value has kind *
. 确实,值可以居住的任何“类型” [2]都具有种类
*
。 If it has any other kind, there can't be any values of it (it is just used as to construct proper types elsewhere). 如果有其他类型,则不能有任何值(它仅用于在其他位置构造适当的类型)。
So, within the signature of tofu
, the following holds 因此,在
tofu
的签名中,以下内容成立
j a :: *
t a j :: *
because they are used as "inhabited" types, since they are arguments to (->)
. 因为它们是
(->)
参数,所以被用作“有人居住”类型。
And these are the only things constraining the class. 这些是唯一限制班级的事情。 In particular,
a
can be any kind. 特别是,
a
可以是任何种类。 With PolyKinds
[3] 使用
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 ->
So we found the required kind of t
. 因此,我们找到了必需的
t
。
We can use a similar reasoning for Frank
. 我们可以对
Frank
使用类似的推理。
data Frank a b = Frank {frankField :: b a}
^^^^^^^^^ ^^^
Again the highlighted bits have to have kind *
, because they can have values. 同样,突出显示的位必须具有kind
*
,因为它们可以具有值。 Otherwise there are no constraints. 否则没有约束。 Generalizing, we have
概括地说,我们有
a :: k
b :: k -> *
Frank a b :: *
And thus 因此
Frank :: k -> (k -> *) -> *
We can see that Frank
's kind matches the required kind for Tofu
. 我们可以看到
Frank
)的种类与Tofu
所需的种类相匹配。 But it also makes sense for a more specific kind, for example: 但这对于更具体的种类也很有意义,例如:
data KatyPerry a b = KatyPerry a (b Int)
Try to deduce her kind, and check that it is more specific than the kind required by Tofu
. 尝试推断出她的种类,并检查它是否比
Tofu
所需的种类更具体。
[1] This is even true of arrows at the kind level if we assume TypeInType
. [1]如果我们假设
TypeInType
,则在种类级别的箭头上也是TypeInType
。 Without TypeInType
, the "kinds of kinds" are called sorts and nobody worries about them; 没有
TypeInType
,“种类”被称为排序 ,没有人担心它们。 there's usually nothing interesting happening at that level. 在那个级别上通常没有什么有趣的事情发生。
[2] I put "type" in quotes because technically only things with kind *
are called types, everything else is called a type constructor . [2]我将“类型”用引号引起来,因为从技术上讲,只有具有
*
东西称为类型,其他所有东西都称为类型构造函数 。 I tried to be precise about this but I couldn't find a non-awkward way to refer to both at once and the paragraph got very messy. 我试图做到这一点很精确,但是我找不到一次同时引用两者的非笨拙方式,因此该段变得非常混乱。 So "type" it is.
所以是“类型”。
[3] Without PolyKinds
, anything with an unconstrained kind like k
gets specialized to *
. [3]如果没有
PolyKinds
,则任何不受限制的种类(如k
都将专门用于*
。 It also means that Tofu
's kind could depend on what type you first happen to instantiate it at, or whether you instantiate it at a type in the same module or a different module. 这也意味着
Tofu
的类型可能取决于您首先遇到的实例化类型,还是取决于您是在同一模块中还是在不同模块中进行实例化。 It's bad. 这不好。
PolyKinds
is good. PolyKinds
很好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.