对类型 类 和 Haskell 中的变量赋值的误解

Misconception on Type Classes and variable assignment in Haskell

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

所以,请...导致这种情况的变量是什么?从非函数式编程的背景来看,它 "looks" 就像我有一个函数 returns 一个类型实现 Num 的值,并试图将它分配给一个类型实现 Num 的变量。然而,分配失败。

我确定这是我的一些基本误解。这可能是阻止第一个示例工作的同一件事。在我开始犯更严重的概念错误之前,我真的很想弄清楚它。

i :: a; i = 1

My expectation was that, since i was typed as generically as possible, I should be able to assign absolutely anything to it. (I know that I probably can't do anything with variable i, but that wasn't important.)

不对,恰恰相反。该类型表示该值 以后如何使用 ,即它声明用户可以使用 i 假装它是当时可能需要的任何类型。本质上,用户选择 a 实际是什么类型,定义 i :: a 的代码必须符合用户的任何此类选择。

(顺便说一下,我们通常称 i = 1“绑定”或“定义”,而不是“赋值”,因为这意味着我们可以稍后重新赋值。)

gg :: Num a => a; gg = g 1.3
(error)

同样的原则也适用于此。 gg 声称是用户可能想要的任何数字类型,但如果用户稍后选择 Int 定义 g 1.3 不符合 Int.

用户可以使用显式签名 (print (gg :: Int)) 选择类型,或将其置于“强制”类型的上下文中(print (length "hello" + gg) 强制 Int 因为 length returns Int).

如果你对其他一些语言的“泛型”比较熟悉,可以和这段代码做个对比:

-- Haskell
i :: a
i = 1            -- type error

-- pseudo-Java
<A> A getI() {
  return 1;      -- type error
}

从更理论的角度来看,您正在考虑错误的量词。当你写 i :: a 时,你在想 i :: exists a . a(不是真正的 Haskell 类型),它读作“i 是某种类型的值(在定义时选择)” .而在 Haskell 中,i :: a 表示 i :: forall a . a,读作“i 是所有类型的值(使用时可能需要的任何类型)”。因此,它归结为“存在”与“forall”,或“谁选择类型 a 实际上是什么”。