答案 0 :(得分:8)
答案 1 :(得分:4)
类比通常缺乏各种各样的方式,但既然你知道C#我认为这可能会有所帮助。
这就是我在C#中描述List a
定义的方法,也许这会清除一些事情(或者更可能让你更加困惑)。
class List<A>
{
}
class Nil<A> : List<A>
{
public Nil() {}
}
class Cons<A> : List<A>
{
public A Head;
public List<A> Tail;
public Cons(A head, List<A> tail)
{
this.Head = head;
this.Tail = tail;
}
}
如你所见;
List
类型有一个类型参数(<A>
),Nil
构造函数没有任何参数,Cons
构造函数有两个参数,类型为head
的值为A
,类型为tail
的值为List<A>
。现在,在Haskell中,Nil
和Cons
只是List a
数据类型的构造函数,在C#中它们本身也是类型,所以这就是类比失败的地方。
但是我希望这能让你直观地了解不同的A
代表什么。
(并且请评论这种可怕的比较如何不公正Haskell的数据类型。)
答案 2 :(得分:3)
Cons a (List a)
Cons的第一个字段是“a
”类型的值。第二个是类型为“List a
”的值,即使用与当前列表的参数相同类型参数化的List。
答案 3 :(得分:3)
5是错误的,我会说如下6替换两者:
缺点{1} a {2}(列表a){3}是一个名为Cons({1}之前的部分)的构造函数,用于需要两个值的类型List a(数据List a part)的值:类型a({1}和{2}之间的部分)和类型列表a之一({2}和{3}之间的部分)。
为了帮助您解决明显的混淆:在Haskell中,您几乎不必提供显式类型参数 - 类型推断从您的值中推断出类型。所以从某种意义上说,当你将值传递给函数或构造函数时,你也可以指定一个类型,即。传入值的类型。
答案 4 :(得分:3)
是的,数据语法有点令人困惑,因为它包含了名称和类型,并没有真正区分它们之间的语法。特别是在构造函数定义中:
Cons a (List a)
第一个单词是构造函数的名称;每个其他单词都是某些预先声明的类型的名称。因此,a
和List a
已经在范围内(a
已被“a
”中的data List a
带入范围,您就是说这些是参数的类型。通过使用记录语法来说明相同的事情,可以更好地证明他们的角色:
Cons { headL :: a, tailL :: List a }
即。类型为List Int
的值,如果是使用Cons
构造函数构建的,则有两个字段:Int
和List Int
。如果它是用Nil
构造的,则它没有字段。
答案 5 :(得分:2)
当我输入“
Cons 0 Nil
”时,它使用“Cons
”值构造函数来创建List的实例。从0开始,它获知类型参数是“Integer
”。到目前为止,没有混乱。但是,它还确定Cons的第一个字段的值为0.但它没有确定第二个字段的值...它只确定第二个字段的类型为“List Integer”
不,它确定第二个字段的值为Nil
。根据您的定义,Nil
是List a
类型的值。因此Cons 0 Nil
也是如此。在Cons 1 it
中,第二个字段的值为it
;即Cons 0 Nil
。这正是REPL所展示的:
Cons 1 (Cons 0 Nil)
。
答案 6 :(得分:1)
我看了你编辑过的问题。
当我使用Cons创建实例时 值构造函数,那些实例 “解释”第一个'a'作为意义 “把价值放在这里。
在“缺点(列表a)”中,“a”和“列表a”都是类型。我不明白它的“价值”是什么。
当我输入“Cons 0 Nil”时,它会使用 “Cons”值构造函数创建一个 列表的实例。它从0开始学习 type参数是“Integer”。 到目前为止,没有混乱。
然而,它也决定了 缺点的第一个字段的值 是0.但它没有任何决定 第二个字段的价值......它 只确定第二个字段 有一种“List Integer”。
第二个字段的值为Nil
。
所以我的问题是,为什么“a”在 第一个字段意思是“这个类型 字段是'a'和它的值 字段是'a'“,而”a“在第二个字段中 字段仅表示“此类型 字段是'列表'?“
第一个字段中的“a”表示“此字段的类型为'a'”。第二个字段中的“列表a”表示“此字段的类型为'列表a'”。在上面的“缺点0”的情况下,“a”被推断为“整数”。因此“Cons a(List a)”变为“Cons Integer(List Integer)”。 0是Integer类型的值。 Nil是“List Integer”类型的值。
此字段的值为“a”
我不明白你的意思。 'a'是一个类型变量;它与价值观有什么关系?
答案 7 :(得分:0)
只是为了给你一些额外的“帮助”,万一你还在看这个帖子。 Haskell有一些约定会弄乱别人关于事情应该如何完成的想法 - 在Haskell中,参数化类型是如此普遍接受的,它通常被认为是一个类型级函数。同样,值构造函数被认为是“特殊”函数,它们也允许模式匹配,除了它们“取值(或更多)并产生值作为结果”。
Haskell的另一个“有趣”特征是它没有显式(或隐式)评估函数的参数,即使该参数在括号中。让我稍微说一点:Haskell函数不会在其他参数之前评估括号中的参数。参数放在括号中仅用于分组目的,而不是“首先”评估它们。 Haskell为一个函数赋予(“apply”)一个比任何其他操作更高优先级的参数 - 甚至高于它自己的一个参数的隐式函数应用程序。这就是为什么Cons
构造函数在第二个参数(List a)
周围有parens - 告诉编译器Cons
有两个参数,而不是三个。括号仅用于分组,而不是优先级!
作为一个侧面话题,请注意F#中的类型。由于F#的根源是ML,因此其参数化类型的参数位于前面 - int list
,而不是(List Int
)! Haskell以另一种方式做到了,因为它与Haskell的功能相同 - 首先是函数,然后是函数的参数。这鼓励了一个共同使用模式,并解释了为什么Haskell类型和值构造函数是大写的 - 提醒您正在处理类型/类相关的事情。
好的,我已经完成了;谢谢你让我把这个巨大的Wall O'Text放在你的财产上......