对Haskell中类型类和变量赋值的误解
Haskell是个新手,他试图理解类型类和变量是如何交互的 我玩的第一件事是:对Haskell中类型类和变量赋值的误解,haskell,types,variable-assignment,typeclass,parametric-polymorphism,Haskell,Types,Variable Assignment,Typeclass,Parametric Polymorphism,Haskell是个新手,他试图理解类型类和变量是如何交互的 我玩的第一件事是: i :: a; i = 1 我的期望是,既然我是尽可能一般地键入的,我就应该能够为它分配任何内容。(我知道我可能无法使用变量I做任何事情,但这并不重要。) 但是,我错了。以上给出了一个错误,并要求其为: i :: Num a => a; i = 1 在玩了一番之后,我想到了以下几点: g :: Num a => a -> a; g a = a + 1 g 1 (returned 2) gg ::
i :: a; i = 1
我的期望是,既然我是尽可能一般地键入的,我就应该能够为它分配任何内容。(我知道我可能无法使用变量I做任何事情,但这并不重要。)
但是,我错了。以上给出了一个错误,并要求其为:
i :: Num a => a; i = 1
在玩了一番之后,我想到了以下几点:
g :: Num a => a -> a; g a = a + 1
g 1
(returned 2)
gg :: Num a => a; gg = g 1
gg
(returned 2)
好的。。。到现在为止,一直都还不错。让我们试试分数参数
g :: Num a => a -> a; g a = a + 1
g 1.3
(returned 2.3)
gg :: Num a => a; gg = g 1.3
(error)
所以,请。。。导致这种情况的变量是什么?从非函数编程背景来看,“看起来”我有一个函数,它返回一个具有实现Num的类型的值,并试图将其分配给具有实现Num的类型的变量。但是,分配失败
我肯定这是我的一些基本误解。这可能是阻止第一个示例工作的原因。我真的想在我开始犯更严重的概念错误之前把它弄清楚
我的期望是,既然我是尽可能一般地键入的,我就应该能够为它分配任何内容。(我知道我可能无法使用变量I做任何事情,但这并不重要。)
不,相反。该类型表示以后如何使用该值,即它表示用户可以使用i
,假装该值属于当时可能需要的任何类型。本质上,用户选择类型a
实际上是什么,定义i::a
的代码必须符合用户的任何此类选择
(顺便说一下,我们通常将i=1
称为“绑定”或“定义”,而不是“分配”,因为这意味着我们以后可以重新分配。)
同样的原则在这里也适用gg
声称是用户可能想要的任何数字类型,但是如果用户以后选择,比如说,Int
则定义g1.3
不适合Int
用户可以使用显式签名选择类型(print(gg::Int)
),或者将其放入“强制”类型的上下文中(print(length“hello”+gg)
强制Int
,因为length
返回Int
)
如果您熟悉其他一些语言中的“泛型”,可以与以下代码进行比较:
-- Haskell
i :: a
i = 1 -- type error
-- pseudo-Java
<A> A getI() {
return 1; -- type error
}
——哈斯克尔
i::a
i=1——类型错误
--伪Java
A getI(){
返回1;--类型错误
}
从更理论的角度来看,你认为量词是错误的。当您编写
i::a
时,您认为i::a存在。一种
(不是真正的Haskell类型),其内容为“i
是某种类型的值(在定义时选择)”。相反,在Haskelli::a中,i::a的意思是i::for all a。一个
,读作“i
是所有类型的值(使用时可能需要的任何类型)”。因此,它可以归结为“存在”与“forall”,或者“谁选择a
实际是什么类型”既然你写的是g1.3
,这意味着类型更“受限”gg
具有as typegg::Fractional a=>a
。但是请注意(除非在某些罕见的情况下),您不应该键入变量,Haskell将始终使用最通用的类型。你没有给变量赋值,你只是声明了一个变量:一旦赋值,你就再也不能改变它的值了。很抱歉:i分数的第一部分是“class Num a=>分数a”。这难道不意味着分数实现了类型类Num吗?或者,是因为我对函数和变量感到困惑。函数参数必须实现特定的类型类,但变量只能接受某些类型?我如何键入一个变量来接收来自g的结果?仅仅从g的类型定义开始?刚刚看到你的编辑。。。我想知道键入变量是否是一个糟糕的举动。我猜是这样。@MarcL.Allen:一个类型要成为fractive
typeclass的成员,它必须是Num
typeclass的成员,这是正确的,因此这意味着fractive
比Num
typeclass更“具体”,因为更多的成员(如Int
)可以是Num
typeclass的成员,但不能是分数类型的成员。在类型之前,=
不是赋值。这是定义。。哦等一下。。。顿悟可能即将来临…所以i::a
意味着我可以将i
插入任何函数,而不管它的需求是什么?i::a
说i
实现了所有可能的类型类?(编辑:这似乎与您的forall EDIT相匹配)@MarcL.Allen大致上是的。这意味着i
可用于需要Int
、Bool
、字符串
、可能[(Int,Bool)]->字符
或任何其他类型的地方。对于类型类:如果类型类不是空的,即存在某种类型T
实现类的方法(实例ct,其中…
),则i
可以用作T
的值。请注意,值属于类型,类型属于类型类。@DanielWagner我们是否可以始终对纯Haskell值使用“计算”(见下文),而对一元值保留“计算”(见下文)?不一致的术语是ppl很难学习Haskell的原因之一。不,不。关于Haskell的值如何不是空函数,也有很多来自大炮的东西。如果有的话,我更喜欢“名称”而不是变量,或“命名值”,或“绑定”。但“变量”也可以。在数学中,它们被称为变量,也是常量re:纯价值,一切都是纯价值
gg :: Num a => a; gg = g 1.3
(error)
-- Haskell
i :: a
i = 1 -- type error
-- pseudo-Java
<A> A getI() {
return 1; -- type error
}