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

时间:2019-05-01 17:45:59

标签: 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 :: 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的类型的变量。但是,分配失败。

我确定这是我的一些基本误解。可能是同一件事使第一个示例无法正常工作。我真的很想弄清楚它,然后再开始犯更严重的概念错误。

1 个答案:

答案 0 :(得分:9)

i :: a; i = 1
     

我的期望是,由于我被尽可能通用地键入,因此我应该能够为其分配绝对的任何内容。 (我知道我可能无法对变量i做任何事情,但这并不重要。)

不,相反。该类型表示以后如何使用该值 ,即,它表示用户可以使用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返回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是所有类型的值(使用时可能需要的任何类型)”。因此,可以归结为“存在”还是“全部”,或者归结为“谁选择a类型实际上是什么类型。”