理解“newtype”关键字

mra*_*a99 2 haskell newtype

对于 uni 作业,我们得到了一行 Haskell 代码,其中显示:

newtype TC a = TC ([Id] -> Either TypeError ([Id], a))
Run Code Online (Sandbox Code Playgroud)

首先,TypeError这是我们需要为分配而实现的东西,所以我不能在这里发布数据声明,但我的问题是这样的。我如何阅读上面的代码?a后面的右边是什么newtype TC?我也不明白如何TC在等号右侧重用。

我认为a这是一个类型变量,因为newtype其工作原理与数据类似。我不知道知道这一点对我的理解有何帮助。

lef*_*out 6

a后面的右边是什么newtype TC

anewtype 声明中的

newtype TC a = ...
Run Code Online (Sandbox Code Playgroud)

x与函数声明中的the 表达大致相同

f x = ...
Run Code Online (Sandbox Code Playgroud)

a是一个类型参数。因此,您将能够使用TCas 或 ,TC Int类似于TC Bool使用flikef 1f "bla bla"(取决于其类型)。

该情况TC Int相当于以下替代方案:

newtype TCInt = TCInt ([Id] -> Either TypeError ([Id], Int))
Run Code Online (Sandbox Code Playgroud)

我也不明白如何TC在等号右侧重用。

这在 Haskell 中是一个令人困惑的怪癖。实际上TC没有被重用,而是声明了两个单独的实体,它们都被称为TC. 你也可以用不同的方式称呼它们:

newtype TC_T a = TC_V ([Id] -> Either TypeError ([Id], a))
Run Code Online (Sandbox Code Playgroud)
  • TC_T是一个类型构造函数。这是将出现在类型签名中的内容,即TC_T IntTC_T Bool
  • TC_V是一个值构造函数。当生成TC_T Int或类型的值时可以使用它TC_T Bool

例如,您可以这样写:

tci :: TC_T Int
tci = TC_V (\ids -> Right (ids, 37))

tcb :: TC_T Bool
tcb = TC_V (\ids -> Right (reverse ids, False))
Run Code Online (Sandbox Code Playgroud)

对于您的原始版本,它看起来像这样:

tci :: TC Int
tci = TC (\ids -> Right (ids, 37))

tcb :: TC Bool
tcb = TC (\ids -> Right (reverse ids, False))
Run Code Online (Sandbox Code Playgroud)

...但它仍然是两个独立的东西,都TV在这里调用。Haskell 中的大多数新类型都以相同的方式调用类型构造函数和值构造函数,但通常只有类型构造函数从模块中导出,而值构造函数则作为实现细节保留。

data其中大部分内容与 for相同newtype。你也可以有

data TC a = TC ([Id] -> Either TypeError ([Id], a))
Run Code Online (Sandbox Code Playgroud)

...与 newtype 版本的唯一区别是微妙的间接寻址:如果它是data,那么编译器会插入一个允许更多惰性的间接寻址,但在这种情况下几乎没有必要这样做。

data在实践中,通常仅在需要多个构造函数和/或具有多个字段的构造函数时使用,这newtype是不支持的。

  • @mraya99 `a` 可以是任何任意类型:`TC (Int, String)`、`TC [Bool]`、`TC (Maybe Bool`、`TC (Bool -> [(Int, String)])` 是全部有效。请注意,在“TC (Int, String)”中,我们没有传递一对类型(即两个类型参数),但我们将“TC”应用于元组的类型(也称为产品类型)在 Haskell 中写为 `(Int, String)`。因此,迂腐地说,`a` 不能是类型的元组,但它可以是元组的(单一)类型。 (2认同)