gpt4 book ai didi

haskell - 类型类和重载,有什么联系?

转载 作者:行者123 更新时间:2023-12-03 14:29:31 25 4
gpt4 key购买 nike

我目前正在尝试围绕类型类和实例进行思考,但我还不太了解它们的意义。到目前为止,我对此事有两个问题:

1)当函数使用该类型类中的某个函数时,为什么必须在函数签名中具有类型类。例子:

f :: (Eq a) => a -> a -> Bool
f a b = a == b

为什么放 (Eq a)在签名中。如果 ==未为 a 定义那为什么不直接在遇到 a == b 时抛出错误? ?必须提前声明类型类有什么意义?

2) 类型类和函数重载有什么关系?

这是不可能的:
data A = A
data B = B

f :: A -> A
f a = a

f :: B -> B
f b = b

但可以这样做:
data A = A
data B = B

class F a where
f :: a -> a

instance F A where
f a = a

instance F B where
f b = b

那是怎么回事?为什么我不能有两个同名但在不同类型上运行的函数……来自 C++,我觉得这很奇怪。但我可能对这些东西到底是什么有错误的概念。但是一旦我将它们包装在这些类型类实例中,我就可以了。

也可以随意向我 throw 类别或输入理论词,因为我在学习这些主题的同时学习 Haskell,我怀疑这些主题中有 Haskell 如何在这里做事的理论基础。

最佳答案

我同意 Willem Van Onsem’s answer 的大部分内容,但我认为它忽略了类型类相对于真正的临时重载的主要优势之一:抽象 .想象一下,我们使用临时重载而不是类型类来定义 Monad操作:

-- Maybe
pure :: a -> Maybe a
pure = Just

(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Just x >>= f = f x
Nothing >>= _ = Nothing

-- Either
pure :: a -> Either e a
pure = Right

(>>=) :: Either e a -> (a -> Either e b) -> Either e b
Right x >>= f = f x
Left err >>= _ = Left err

现在,我们知道每个 monad 都可以用 pure 表示。和 >>= , 同上,但我们也知道它们可以用 fmap 等价表示, pure , 和 join .因此,我们应该能够实现 join适用于任何 monad 的函数:
join x = x >>= id

然而,现在我们遇到了一个问题。什么是 join的类型?

显然, join必须是多态的,因为它可以在任何单子(monad)上工作。但是给它类型签名 forall m a. m (m a) -> m a显然是错误的,因为它不适用于所有类型,仅适用于单子(monad)类型。因此,我们需要在我们的类型中表达需要存在一些操作 (>>=) :: m a -> (a -> m b) -> m b。 ,这正是 typeclass 约束所提供的。

鉴于此,很明显,即席重载使重载名称成为可能,但不可能对这些重载名称进行抽象,因为无法保证不同的实现以任何方式相关。你可以定义没有类型类的 monad,但是你不能定义 join , when , unless , mapM , sequence ,以及仅定义两个操作时免费获得的所有其他好东西。

因此,在 Haskell 中需要类型类来实现代码重用并避免大量重复。但是你能同时拥有类型类风格的重载和类型导向的临时名称重载吗? ,事实上, idris 确实如此。但是 Idris 的类型推断与 Haskell 的非常不同,因此由于 Willem 的回答中的许多原因,支持它比在 Haskell 中更可行。

关于haskell - 类型类和重载,有什么联系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47971360/

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