繁体   English   中英

在上下文中使用数据构造函数

[英]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]

这就是所谓的通用量化 ,您可能已经知道,这意味着对于您选择的任何类型ABmap都可以使用,就好像它具有签名(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签名中的ab现在与顶层使用的类型相同。

  • 允许参数是多态的。 这称为高级多态性。 问题类似于上面的问题:正如我所说,本地绑定的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM