Haskell ad hoc多态性

温斯

我试图避开haskell中的即席多态性,即具有相同的功能为不同的参数类型提供不同的行为。

但是尽管以下测试代码可以编译

{-# LANGUAGE MultiParamTypeClasses #-}

class MyClass a b where
    foo :: a -> b

instance MyClass Bool Int where
    foo True = 0
    foo False = 1

instance MyClass Double Double where
    foo x = -x

如果我尝试使用类似的名称

foo True

ghci对我大喊:

No instance for (MyClass Bool b0) arising from a use of `foo'
The type variable `b0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there is a potential instance available:
  instance MyClass Bool Int -- Defined at test.hs:6:10
Possible fix: add an instance declaration for (MyClass Bool b0)
In the expression: foo True
In an equation for `it': it = foo True

但是,如果指定返回类型,则可以使用:

foo True :: Int -- gives 0

为什么需要这个?Bool的参数类型应足以解决歧义。

另外:这是实现类似行为的“最佳”方法吗?(无需将功能重命名为fooBoolfooDouble

蒂洪·杰维斯

您面临的问题是,重载由类中的所有类型(包括仅作为返回类型出现的类型)确定。你可以有实例两个MyClass Bool IntMyClass Bool String,这将能够基于什么类型有望消除歧义。

Haskell类型类的核心设计折衷之一是“开放世界假设”。Haskell类型实例是隐式全局的:特定类型(在这种情况下为类型序列)在整个程序中只能有一个实例,该实例将隐式导出到使用该类型的所有模块。

这使获取某个类的新实例变得非常容易而又无需意识到它,因此Haskell类型检查器假定实例对于任何有效的类型组合可能存在。在您的情况下,这意味着尽管虽然MyClass Bool Int是唯一使用的实例Bool,但它与其他可能的MyClass Bool b实例仍然不明确

一旦为整个表达式的类型添加了注释,它就不再是模棱两可的,因为两者ab都是固定的。

要获得您期望的行为,可以使用FunctionalDependencies这允许你指定只有有一个可能b对于任何给定a,这将让正确推断GHC的类型。它看起来像这样:

class MyClass a b | a -> b where

当然,这不故意扔了一定的灵活性:现在你不能有两个实例MyClass Bool IntMyClass Bool String

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章