在Haskell中包含具有默认实现的类型类

时间:2010-12-17 10:33:12

标签: haskell typeclass

考虑以下定义:

class Foo a where
    foo :: a -> Int

class Bar a where
    bar :: a -> [Int]

现在,我怎么说“每个Foo也是Bar,默认情况下bar在Haskell中定义为bar x = [foo x]

(无论我尝试什么,编译器都会给我“非法实例声明”“约束不小于实例头”

顺便说一句,我可以通过其他方式定义我的FooBar类,如果这样做有帮助的话。

3 个答案:

答案 0 :(得分:11)

class Foo a where
    foo :: a -> Int

-- 'a' belongs to 'Bar' only if it belongs to 'Foo' also
class Foo a => Bar a where
    bar :: a -> [Int]
    bar x = [foo x] -- yes, you can specify default implementation

instance Foo Char where
    foo _ = 0

-- instance with default 'bar' implementation
instance Bar Char

答案 1 :(得分:4)

由于通过Bar实例自动定义Foo实例会导致编译器出现不可判定的情况 - 即一个显式实例和一个通过Foo相互冲突 - ,我们需要一些特殊选项来允许所需的行为。其余的通过非常简单。

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

class Foo a where
    foo :: a -> Int

class Bar a where
    bar :: a -> [Int]

instance (Foo a) => Bar a where
    bar x = [foo x]

答案 2 :(得分:4)

一般来说,你不用这种方式用类型类来建模事物[*] - 即类型类的实例应该总是某种具体类型,尽管这种类型本身可以是参数的 - 例如对的Show实例具有以下签名:

instance (Show a, Show b) => Show (a,b) where

“泛型”的一些方法允许您对一般基本案例进行建模,然后具有特定类型的例外情况。 SYB3允许这个 - 也许不幸的是SYB3不是通用的Generics库,它是Data.Data / Data.Generics,我认为它是SYB1。

[*]在野外,这个故事有点复杂 - 正如Dario所说,UndecidableInstances可以启用它。