gpt4 book ai didi

haskell - forall 在上下文中与数据构造函数

转载 作者:行者123 更新时间:2023-12-02 08:12:19 25 4
gpt4 key购买 nike

我阅读了HaskellWiki关于数据构造函数并考虑以下内容:

2.1 Data constructors as first class values

Data constructors are first class values in Haskell and actually have a type. For instance, the type of the Left constructor of the Either data type is:

Left :: forall b a. a -> Either a b

As first class values, they may be passed to functions, held in a list, be data elements of other algebraic data types and so forth.

上面的forall是什么意思?

最佳答案

quantor, aka forall , 在所有 多态 Haskell 签名中以一种或另一种方式隐式使用。例如,

map :: ∀ a b . (a -> b) -> [a] -> [b]

这称为通用量化,您可能知道这意味着对于任何类型AB 您选择的 map 可以像具有签名 (A -> B) -> [A] -> [B] 一样使用。

在 Haskell98 中,这种在签名开头使用 ∀ a 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 重新使用了已经绑定(bind)在 foldl f = ... 模式中的相同 f,并且是不是多态的(此时类型已经固定),因此不可能选择独立的a'b' 类型变量在go中。
    解决方案是启用作用域类型变量,然后显式写入

    {-# 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 签名中的 ab 现在与顶层使用的类型相同。

  • 允许参数是多态的。这称为高阶多态性。这个问题与上面的问题类似:正如我所说,本地绑定(bind)的 f不是多态的。 (通常不可能——您希望能够将 foldl 与特定于一种特定元素类型的函数一起使用!)
    但在某些应用程序中,多态函数作为和参数您想要的。例如,您可能有一个类型可以同时对精确有理数和快速逼近 float 进行算术运算。

    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)

关于haskell - forall 在上下文中与数据构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45453841/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com