对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 ::

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 :: 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
是某种类型的值(在定义时选择)”。相反,在Haskell
i::a中,i::a的意思是
i::for all a。一个
,读作“
i
是所有类型的值(使用时可能需要的任何类型)”。因此,它可以归结为“存在”与“forall”,或者“谁选择
a
实际是什么类型”

既然你写的是
g1.3
,这意味着类型更“受限”
gg
具有as type
gg::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
}