![](/img/trans.png)
[英]Difference between forall quantifier inside a constructor and outside a constructor
[英]forall in Context with Data constructor
我在HaskellWiki上阅读了有关数据构造函数的内容,并考虑以下内容:
2.1数据构造函数作为一等值
数据构造函数是Haskell中的一等值,实际上具有类型。 例如,Either数据类型的Left构造函数的类型为:
Left :: forall b a. a -> Either ab
作为第一类值,可以将它们传递到保存在列表中的函数,其他代数数据类型的数据元素等。
是什么forall
上面的意思吗?
所有多态Haskell签名中都以一种或另一种方式隐式使用∀
量化器(又名forall
。 例如,
map :: ∀ a b . (a -> b) -> [a] -> [b]
这就是所谓的通用量化 ,您可能已经知道,这意味着对于您选择的任何类型A
和B
, map
都可以使用,就好像它具有签名(A -> B) -> [A] -> [B]
。
在Haskell98中,在签名开始时使用∀abc ∀ abc ...
(出现的所有类型变量)的这种通用量化是唯一可用的多态性,并且它仍然是最重要的。 因此,这是隐式的:当你看到一个签名与小写字母,编译器知道签名真的开始∀
在所有这些变量。 所以你可以简单地写
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 :: ∀ ab . (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
,并且该foldl f = ...
不是多态的(类型已在该点固定),因此无法选择独立的a'
和go
b'
类型变量。
解决方案是启用作用域类型变量 ,然后显式编写
{-# LANGUAGE ScopedTypeVariables #-} foldl :: ∀ ab . (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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.