Haskell特设多态性 [英] Haskell ad hoc polymorphism
问题描述
但是虽然在haskell中有特定的多态性,但它具有相同的功能,可为不同的参数类型提供不同的行为。以下测试代码编译
{ - #LANGUAGE MultiParamTypeClasses# - }
$ b $ class MyClass ab其中
foo :: a - > b
实例MyClass Bool Int其中
foo True = 0
foo False = 1
实例MyClass Double Double其中
foo x = -x
如果我尝试使用类似于
foo真
ghci对我说:
$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $'$'是不明确的
可能的修复:添加修复这些类型变量的类型签名
注意:有一个潜在的实例可用:
instance MyClass Bool Int - 在test.hs中定义: 6:10
可能的修正:为(MyClass Bool b0)
添加一个实例声明在表达式中:foo True
在'it'的等式中:it = foo True
然而,如果我指定了返回类型,它将起作用:
foo True :: Int - 给出0
为什么这是需要的吗? Bool的参数类型应该足以解决歧义。
另外:这是实现类似行为的最佳方式吗? (没有将函数重命名为 fooBool
和 fooDouble
)
您面临的问题是,重载由类中的所有类型确定 - 包括仅显示为返回类型的类型。你可以同时拥有 MyClass Bool Int
和 MyClass Bool String
的实例,并且它可以根据类型是预期的。
这样可以很容易地在没有意识到的情况下获得某个类的新实例,所以Haskell类型检查器假定可能存在类型的有效组合。在你的情况下,这意味着尽管 MyClass Bool Int
是使用 Bool
的唯一实例,但它仍然不明确 MyClass Bool b
实例。
一旦为整个表达式的类型添加注释,它就会停止模糊因为 a
和 b
都是固定的。
获得您期望的行为,您可以使用 FunctionalDependencies
。这些允许你为任何给定的 a
指定只有 1 可能的 b
,这会让GHC正确地推断出类型。它看起来像这样:
class MyClass a b | a - > b其中
当然,这确实会故意抛出一些灵活性:现在您不能拥有实例都是 MyClass Bool Int
和 MyClass Bool String
。
I'm trying to get my head around ad-hoc polymorphism in haskell, that is having the same function provide different behaviour for different argument types.
But while the following test code compiles
{-# 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
if I try to call it using something like
foo True
ghci yells at me:
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
However, if I specify the return type, it works:
foo True :: Int -- gives 0
Why is this needed? The parameter type of Bool should be enough to resolve the ambiguity.
Also: Is this the "best" way to achieve similar behaviour? (without renaming the functions to fooBool
and fooDouble
)
The problem you're facing is that the overloading is determined by all of the types in the class—including ones that only appear as return types. You could have instances for both MyClass Bool Int
and MyClass Bool String
, and it would be able to disambiguate based on what type is expected.
One of the core design tradeoffs with Haskell typeclasses is the "open world assumption". Haskell type instances are implicitly global: a specific type (or sequence of types, in this case) can only have one instance in the whole program, which is implicitly exported to all the modules using that type.
This makes it really easy to get new instances of some class without realizing it, so the Haskell typechecker assumes that instances could possibly exist for any valid combination of types. In your case, this means that while MyClass Bool Int
is the only instance using Bool
, it's still ambiguous with other possible MyClass Bool b
instances.
Once you add an annotation for the type of the whole expression, it stops being ambiguous because both a
and b
are fixed.
To get the behavior you expect, you can use FunctionalDependencies
. These allow you to specify that there is only one possible b
for any given a
, which will let GHC infer the type correctly. It would look something like this:
class MyClass a b | a -> b where
Of course, this does intentionally throw out some flexibility: now you can't have instances for both MyClass Bool Int
and MyClass Bool String
.
这篇关于Haskell特设多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!