gpt4 book ai didi

haskell - 多态性:常数与函数

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

我是 Haskell 的新手,在 Haskell Programming from First Principles 书中遇到了一个让我有点困惑的例子。在第 6 章结束时,我突然想到以下内容不起作用:

constant :: (Num a) => a
constant = 1.0

但是,以下工作正常:
f :: (Num a) => a -> a
f x = 3*x

我可以为 x 输入任何数值进入函数 f什么都不会破坏。它不限于取整数。这对我来说很直观。但是常数的例子让我完全困惑。

在reddit上 thread对于这本书,解释(解释)常量示例不起作用的原因是类型声明强制 constant 的值仅是不比 Num 更具体的事物.所以试图给它分配一个值,它来自 Num 的子类喜欢 Fractional不是犹太教的。

如果这个解释是正确的,那么我认为这两个例子似乎完全相反是错误的吗?在一种情况下,类型声明强制值尽可能通用。在另一种情况下,函数的可接受值可以是实现 Num 的任何值。 .

谁能让我直截了当?

最佳答案

有时,将类型理解为两个参与者(类型的实现者和类型的用户)之间玩的游戏会有所帮助。为了很好地解释这个观点,我们必须介绍一些 Haskell 默认对你隐藏的东西:我们将为所有类型变量添加绑定(bind)器。所以你的类型实际上会变成:

constant :: forall a. Num a => a
f :: forall a. Num a => a -> a

现在,我们将这样阅读类型形成规则:
  • forall a. t表示:调用者选择类型a ,游戏继续为t
  • c => t表示:调用者显示约束 c成立,游戏继续t
  • t -> t'表示:调用者选择类型为 t 的值,游戏继续为t'
  • t (其中 t 是单态类型,例如裸变量或 Integer 或类似的)意味着:实现者产生类型为 a 的值

  • 我们需要一些其他的细节来真正理解这里的东西,所以我会在这里快速说出来:
  • 当我们写一个没有小数点的数字时,编译器会隐式地将其转换为对 fromInteger 的调用。应用于Integer通过解析该数字产生。我们有fromInteger :: forall a. Num a => Integer -> a .
  • 当我们写一个带小数点的数字时,编译器会隐式地将其转换为对 fromRational 的调用。应用于Rational通过解析该数字产生。我们有fromRational :: forall a. Fractional a => Rational -> a .
  • Num类包括方法(*) :: forall a. Num a => a -> a -> a .

  • 现在让我们尝试缓慢而仔细地浏览您的两个示例。
    constant :: forall a. Num a => a
    constant = 1.0 {- = fromRational (1 % 1) -}
    constant的类型说:调用者选择了一个类型,说明这个类型实现了 Num ,然后实现者必须产生该类型的值。现在实现者尝试通过调用 fromRational :: Fractional a => Rational -> a 来玩他自己的游戏。 .他选择了与调用者相同的类型,然后尝试表明该类型实现了 Fractional。 .哎呀!他无法证明这一点,因为来电者向他证明的唯一一件事就是 a实现 Num -- 这不能保证 a还实现了 Fractional .当。所以 constant 的实现者不允许调用 fromRational在那种类型。

    现在,让我们看看 f :
    f :: forall a. Num a => a -> a
    f x = 3*x {- = fromInteger 3 * x -}
    f的类型说:调用者选择了一个类型,表明该类型实现了 Num , 并选择该类型的值。然后,实现者必须生成该类型的另一个值。他将通过与 (*) 玩自己的游戏来做到这一点。和 fromInteger .特别是,他选择了与调用者相同的类型。但是现在 fromInteger(*)只要求他证明这个类型是 Num 的一个实例——所以他放弃了来电者给他的证明,从而挽救了局面!然后他选择 Integer 3对于 fromInteger 的参数, 并选择这个结果和调用者交给他的值作为 (*) 的两个参数.每个人都很满意,实现者可以返回一个新值。

    整个展览的重点是: Num两种情况下的约束都强制执行完全相同的事情,即我们选择实例化的任何类型 a at 必须是 Num 的成员类(class)。只是在定义 constant = 1.0Num不足以完成我们编写的操作,而在 f x = 3*xNum足以完成我们编写的操作。而且由于我们为这两件事选择的操作是如此不同,所以一个有效而另一个无效也就不足为奇了!

    关于haskell - 多态性:常数与函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39281442/

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