Haskell特设多态性 [英] Haskell ad hoc polymorphism

查看:104
本文介绍了Haskell特设多态性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



但是虽然在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类型类的核心设计权衡之一是开放世界假设。 Haskell类型实例隐式地是全局的:在整个程序中,一个特定的类型(或者这种情况下的类型序列)只能有一个实例,隐式地导出到所有使用该类型的模块。

这样可以很容易地在没有意识到的情况下获得某个类的新实例,所以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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆