对Haskell中类型类和变量赋值的误解[重复]

问题描述 投票:4回答:1

这个问题在这里已有答案:

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)

好的...到目前为止一切顺利。我们来试试一个Fractional参数。

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的类型的变量。然而,任务失败了。

我确信这是我的一些基本误解。阻止第一个例子工作可能是同样的事情。在我开始制造更严重的概念错误之前,我真的想让它理顺。

haskell types variable-assignment typeclass parametric-polymorphism
1个回答
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是所有类型的值(使用时可能需要的任何类型)”。因此,它归结为“存在”与“forall”,或归结为“谁选择a实际上是什么类型”。

© www.soinside.com 2019 - 2024. All rights reserved.