gpt4 book ai didi

haskell - 与 Haskell 类的混淆

转载 作者:行者123 更新时间:2023-12-02 18:43:42 26 4
gpt4 key购买 nike

我对 Haskell 中的类感到困惑,如下所示。

我可以定义一个采用 Integral 参数的函数,并成功为其提供 Num 参数:

gi :: Integral a => a -> a
gi i = i
gin = gi (3 :: Num a => a)

我可以定义一个采用 Num 参数的函数,并成功为其提供 Integral 参数:

fn :: Num a => a -> a
fn n = n
fni = fn (3 :: Integral a => a)

我可以定义一个 Integral 值并为其分配一个 Num

i :: Integral a => a
i = (3 :: Num a => a)

但是,如果我尝试定义一个 Num 值,然后为其分配一个 Integral 值,则会出现解析错误

- this doesn't work
n :: Num a => a
n = (3 :: Integral a => a)

也许我对我的面向对象背景感到困惑。但是为什么函数变量似乎让你“双向”,即当“期望”父类(super class)时可以提供子类的值,并且当需要子类时可以提供父类(super class)的值,而在赋值时你可以提供将父类(super class)分配给子类值,但无法将子类分配给父类(super class)值?

作为比较,在面向对象编程中,您通常可以将子值分配给父类型,但反之则不然。在 Haskell 中,第二对示例的情况似乎相反。

最佳答案

前两个示例实际上与 NumIntegral 之间的关系没有任何关系。

看一下 ginfni 的类型。让我们一起来做吧:

> :t gin
gin :: Integer

> :t fni
fni :: Integer

发生什么事了?这称为“类型默认”。

从技术上讲,Haskell 中的任何数字文字,如 3542 都具有类型 Num a => a.因此,如果您希望它只是一个整数,该死的,您必须始终编写 42::Integer 而不是 42。这非常不方便。

因此,为了解决这个问题,Haskell 有某些规则,在某些特殊情况下,规定当类型变为通用类型时要替换的具体类型。如果同时使用 NumIntegral,默认类型为 Integer

因此,当编译器看到 3 并将其用作 gi 的参数时,编译器默认为 Integer。就是这样。您对 Num a 的附加约束不会产生进一步的影响,因为 Integer 实际上已经是 Num 的实例。


另一方面,对于最后两个示例,区别在于您显式指定了类型签名。你不只是把它留给编译器来决定,不!您特别提到了 n::Num a => a。因此编译器无法再决定 n::Integer 。它必须是通用的。

由于它是通用的,并且被限制为 Num,因此 Integral 类型不起作用,因为,正如您所正确指出的,Num code> 不是 Integral 的子类。

您可以通过为 fni 提供类型签名来验证这一点:

-- no longer works
fni :: Num a => a
fni = fn (3 :: Integral a => a)

等等,但是 n 不应该仍然有效吗?毕竟,在面向对象中这会很好地工作。以 C# 为例:

class Num {}
class Integral : Num {}
class Integer : Integral {}

Num a = (Integer)3
// ^ this is valid (modulo pseudocode), because `Integer` is a subclass of `Num`

啊,但这不是泛型类型!在上面的示例中,a 是具体类型 Num 的值,而在 Haskell 代码中 a 本身就是一种类型,但仅限于是Num。这更像是 C# 接口(interface),而不是 C# 类。

泛型类型(无论是否在 Haskell 中)实际上是相反的!取这样的值:

x :: a
x = ...

这个类型签名的意思是“谁需要x,就来拿吧!但是首先命名一个类型a。然后是值 x 将属于该类型。无论您命名哪种类型,x 都将是“

或者,更简单地说,选择泛型类型的是函数的调用者(或值的使用者),而不是实现者。

因此,如果您说 n::Num a => a,则意味着值 n 必须能够“变形”为任何 类型 a 无论如何,只要该类型有一个 Num 实例。无论谁在计算中使用n - 这个人都会选择a是什么。您,n 的实现者,无权选择它。

由于您无法选择 a 是什么,因此您无法将其缩小为不仅仅是任何 Num,而是一个 >整体。因为,你知道,有一些 Num 不是 Integral,所以如果使用 n 的人选择,你会怎么做那些非Integral类型之一是a


对于i,这工作得很好,因为每个Integral也必须是Num,所以无论i的使用者是什么 选择 a,您肯定知道它将是 Num

关于haskell - 与 Haskell 类的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67732331/

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