在 Haskell 中,可变性是否总是必须反映在类型系统中?

In Haskell, does mutability always have to be reflected in type system?

我是Haskell的新手,所以如果这个问题很愚蠢,请原谅。

假设我们有两个数据结构绑定到名称 xy.

x 是可变的。

y 不是。

作为一个问题或原则,x 是否一定与 y 具有不同的类型?

简短回答:是的。

在 Haskell 中,所有 变量 在技术上都是不可变的。与 JavaScript 不同,一旦您在 Haskell 中定义了一个新变量并将其绑定到初始值:

let x = expression1 in body1

这是它永远的价值。在 body1 中使用 x 的任何地方,它的值都保证是 expression1 的(固定)值。 (好吧,从技术上讲,您可以在 body1 中定义一个具有相同名称的全新不可变变量 x,然后正文中的某些 x 可能会引用该新变量,但这是完全不同的事情。)

Haskell 确实有可变的 数据结构 。我们通过创建一个新的可变结构并将其绑定到一个不可变变量来使用它们:

do ...
   xref <- newIORef (15 :: Int) 
   ...

这里,xref本身的值不是整数 15。相反,xref 被分配了一个不可变的、不可显示的值,标识一个“容器”,其内容当前为 15。要使用此容器,我们需要明确地从中提取值,我们可以将其分配给不可变变量:

  value_of_x_right_now <- readIORef xref

并明确地将值放入其中:

  writeIORef xref (value_of_x_right_now + 15)

关于这些值,以及通常需要通过 IO 或另一个 monad 中的 monadic 操作访问它们的方式,显然还有很多可以说的。

但是,即使撇开这一点,也应该清楚整数 15 和“内容初始化为整数 15 的容器”是具有必然不同类型的对象。在本例中,类型分别为 IntIORef Int

因此,数据结构的可变性必然会反映在类型级别,仅仅是因为 Haskell 中的可变性是通过这些类型的“容器”实现的,而值与包含该值的容器类型不同。