【问题标题】:Misconception on Type Classes and variable assignment in Haskell [duplicate]Haskell中对类型类和变量赋值的误解[重复]
【发布时间】:2019-09-20 06:19:57
【问题描述】:

对 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 的变量。然而,分配失败。

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

【问题讨论】:

  • 既然你写了g 1.3,这意味着类型更加“受限”,gg 的类型为gg :: Fractional a => a。但是请注意(除非在极少数情况下),您不应该键入变量,Haskell 将始终使用最通用的类​​型。您不为变量分配值,而是声明一个变量:一旦分配了一个值,就不能再更改它的值。
  • 我不明白。对不起。 :i Fractional 的第一部分是“class Num a => Fractional a”。这不是意味着 Fractional 实现了类型类 Num 吗?或者,是不是我对函数和变量感到困惑。函数参数必须实现特定类型类,但变量只能接受某些类型?我将如何键入一个变量来接收来自 g 的结果?仅仅从 g 的类型定义?刚刚看到你的编辑......我想知道输入变量是否是一个糟糕的举动。我想是的。
  • @MarcL.Allen:对于一个类型来说,要成为Fractional 类型类的成员,它必须是Num 类型类的成员,这是正确的,因此这意味着FractionalNum 类型类更“特定”,因为更多成员(如 Int)可以是 Num 类型类的成员,但不是 属于Fractional 类型类。
  • 在类型之前,=not 赋值。它是定义

标签: haskell types variable-assignment typeclass parametric-polymorphism


【解决方案1】:
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 实际是什么类型”。

【讨论】:

  • 哦..哦!等一下……顿悟可能要来了……
  • 所以...i :: a 暗示我可以将i 插入任何功能,无论其要求如何? i :: ai 实现了所有可能的类型类? (编辑:这似乎与您的 forall 编辑相匹配)
  • @MarcL.Allen 粗略地说,是的。这意味着i 可以在您需要IntBoolStringMaybe [(Int, Bool)] -&gt; Char 或任何其他类型的地方使用。对于类型类:如果类型类不为空,即有一些类型T 实现了类的方法(instance C T where ...),那么i 可以用作T 的值。注意值属于类型,类型属于类型类。
  • @DanielWagner 我们是否可以总是对纯 Haskell 值使用“计算”​​(在 Wadler 之后,在 Turner 之后),并为一元值保留“计算”(在 Moggi 之后)?不一致的术语是人们难以学习 Haskell 的原因之一。
  • 不,不。关于 Haskell 的值如何不是空函数,有很多东西,也来自大炮。如果有的话,我更喜欢“名称”而不是变量、“命名值”或“绑定”。但是“变量”也很好。在数学中,它们也被称为变量,并且也是常数。 --- re: 纯值,everything 在 Haskell 中是一个纯值。 x = 7+8y = print x 都是。但是@Daniel 的观点是,由于懒惰,x 不是立即的值——它背后有一个完整的计算 等待。 (这也是你所指的,我相信)。 1/
猜你喜欢
  • 2019-07-20
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 2018-11-02
  • 1970-01-01
相关资源
最近更新 更多