Haskell 使用数据构造函数在上下文中调用 我阅读了有关数据构造函数的文章,并考虑如下:
2.1数据构造函数作为一级值 数据构造函数是Haskell中的第一类值,实际上有一个类型。例如, 任一数据类型的左构造函数的类型为:Haskell 使用数据构造函数在上下文中调用 我阅读了有关数据构造函数的文章,并考虑如下:,haskell,Haskell,2.1数据构造函数作为一级值 数据构造函数是Haskell中的第一类值,实际上有一个类型。例如, 任一数据类型的左构造函数的类型为: 左::对于所有b a。a->a或b 作为第一类值,可以传递它们 to函数,保存在列表中,是其他代数数据的数据元素 类型等等 上述所有的含义是什么 在所有多态Haskell签名中以某种方式隐式使用。比如说, map :: ∀ a b . (a -> b) -> [a] -> [b] 这被称为通用量化,正如您可能知道的,这意味着对于您选择的任何类型
左::对于所有b a。a->a或b
作为第一类值,可以传递它们
to函数,保存在列表中,是其他代数数据的数据元素
类型等等
上述所有的含义是什么 在所有多态Haskell签名中以某种方式隐式使用。比如说,
map :: ∀ a b . (a -> b) -> [a] -> [b]
这被称为通用量化,正如您可能知道的,这意味着对于您选择的任何类型A
和B
,map
都可以使用,就好像它具有签名(A->B)->[A]->[B]
在Haskell98中,此通用量化使用∀ 在签名开始处的一个b c…
(所有发生的类型变量)是唯一可用的多态性,它仍然是最重要的。因此,这是隐式的:当您看到带有小写字母的签名时,编译器知道签名实际上以∀代码>覆盖所有这些变量。所以你可以简单地写
map :: (a -> b) -> [a] -> [b]
这还包括数据构造函数(在表达式中,数据构造函数的行为与任何其他函数一样
Left :: a -> Either a b
但正如我所说,这实际上只是
Left :: ∀ a b . a -> Either a b
或者确实
Left :: forall a b . a -> Either a b
在现代Haskell中,有时有必要使用显式量子,而不是隐式量子
- 要“重用”本地签名中顶级签名中的类型变量,请执行以下操作:
foldl :: (b->a->b) -> b -> [a] -> b
foldl f = go
where go :: b -> [a] -> b
go acc [] = acc
go acc (x:xs) = go (f acc x) xs
问题是,由于其中的类型变量,go
的本地签名意味着一个新的通用量子,即这实际上意味着
foldl :: ∀ a b . (b->a->b) -> b -> [a] -> b
foldl f = go
where go :: ∀ a' b' . b' -> [a'] -> b'
go acc [] = acc
go acc (x:xs) = go (f acc x) xs -- error: could not match a with a'
但是,go
重新使用已绑定在foldl f=…
模式中的相同的f
,并且该模式不是多态的(此时类型已经固定),因此不可能在go
中选择独立的a'
和b'
类型变量
解决方案是启用作用域类型变量,然后显式写入
{-# LANGUAGE ScopedTypeVariables #-}
foldl :: ∀ a b . (b->a->b) -> b -> [a] -> b
foldl f = go
where go :: b -> [a] -> b
go acc [] = acc
go acc (x:xs) = go (f acc x) xs
在这里,GHC知道我不想要隐式量化(因为我已经明确地编写了一个)。因此go
签名中的a
和b
现在与顶层使用的类型相同
- 允许参数具有多态性。这称为高阶多态性。问题与上面的问题类似:正如我所说,局部绑定的
f
不是多态性的。(通常不能是多态性的–您希望能够将foldl
与特定于一种元素类型的函数一起使用!)
但在某些应用程序中,您需要的是多态函数as和参数。例如,您可能有一个类型,它可以对精确有理数和快速近似浮点进行运算
data ApproxAndExact = ApproxAndExact Double Rational
现在您想对这些数字执行操作,但不想复制代码
onBothReprs :: (∀ n . Fractional n => n -> n)
-> ApproxAndExact -> ApproxAndExact
onBothReprs f (ApproxAndExact approx exact)
= ApproxAndExact (f approx) (f exact) -- note that both invocations
-- of f have different types!
然后可以像这样使用它
> obBothReprs (+273) 1e+16
ApproxAndExact 1.0000000000000272e16 (10000000000000273 % 1)
虽然该wiki页面解释了所有
的含义,但请注意,问题中使用的所有
并不构成该页面后面解释的存在类型。该页面中与该问题相关的唯一内容是“所有关键字”部分。这样你就不会感到困惑了。从你的个人资料来看,你似乎很熟悉C#?Left::for all a b.a->a b
就像或Left(a值)
。所有AB的Haskell对应于左侧的C#
——它定义了泛型类型参数的范围。通常这在Haskell中是隐式的,但您可以(有时必须)这样做用“代码”>显式的所有代码>代码>代码> ScopedTypeVariables >代码>或>代码> RankNTypes <代码>扩展。同样,如果使用C++,<>代码> B.< /代码>就像<代码>模板< /代码>。