简体   繁体   English

了解数据类型,类型类的签名,并使数据类型成为类型类的实例

[英]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:在xtofu 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 . 但我不知道如何呈现jax将区分xtofu xjaxFrank xaj

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 我种新的具有数据类型或类的内部的功能的想法(例如: bFrank abtTofu 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 * . 就像bx -> y类型的函数,而ax类型的值一样, ba的类型将是y ,而不是(x -> y) -> x :仅用*替换xy

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. 是应用于xFrank 数据构造 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 ~ ja1 ~ 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM