10

例如,我有一个类型类:

class MyClass a b c where
    fun01 :: a -> b
    fun02 :: a -> c

    fun03 :: a -> b -> c -> ()
    fun04 :: a -> WhatEver

我想为我的提供一个默认实现,让我们称之为它BaseDataType,它定义fun03了 self 和fun01and的实现fun02。然后我会有这样的事情:

class MyClass BaseDataType b c where
    fun03 = fun01 <$> fun02 ...
    fun04 = fun02 ...

而不是完成我的类实例并避免所有样板代码fun03fun04我只是提供fun01fun02喜欢这样:

instance MyClass BaseDataType Int Char where
    fun01 = 1
    fun02 = 'C'

是否有一些语言扩展允许这种行为?我找不到有关此主题的任何内容。

4

2 回答 2

11

没有这样的扩展,但您只需将您的类分成两个类即可实现此功能:

class MyClass1 a b c where
    fun03 :: a -> b -> c -> ()
    fun04 :: a -> WhatEver

class MyClass1 a b c => MyClass2 a b c where    
    fun01 :: a -> b
    fun02 :: a -> c

然后您的实例将按照您想要的方式工作:

-- NB: need the MyClass2 constraint if you use `fun01` or `fun02` in the definitions
-- This requires UndecidableInstances
instance MyClass2 BaseDataType b c => MyClass1 BaseDataType b c where
    fun03 = fun01 <$> fun02 ...
    fun04 = fun02 ...

instance MyClass2 BaseDataType Int Char where
    fun01 = 1
    fun02 = 'C'

您班级的用户不受影响;他们可以继续在以前使用的MyClass2地方消费MyClass并获得完全相同的功能。


MyClass撇开: , and and 的原始定义,MyClass1由于几个MyClass2模棱两可的类型错误(c在类型中没有提到fun01,等等),甚至不编译 - 我假设这个类只是为了演示目的而定义的,我没有尝试过解决这个问题。

于 2017-12-18T16:15:15.163 回答
5

您可以像这样使用 DefaultSignatures

class MyClass a b c where
    fun01 :: a -> b
    fun02 :: a -> c

    fun03 :: a -> b -> c -> ()
    default fun03 :: (a ~ BaseDataType) => a -> b -> c -> ()
    fun03 = fun01 <$> fun02 ...

    fun04 :: a -> WhatEver
    default fun04 :: (a ~ BaseDataType) => a -> WhatEver
    fun04 = fun02 ...
于 2017-12-18T23:17:40.010 回答