双重默认方法

时间:2018-02-05 10:56:16

标签: haskell

考虑以下课程:

class F t where
  f1 :: ...
  f2 :: ...

class F t => G t where
  g1 :: ...
  g2 :: ...

我也可以编写以下默认函数:

  1. f1f2而言。
  2. f2f1而言。
  3. g1g2而言。
  4. g2g1而言。
  5. f1g1而言G t
  6. f2g2而言G t
  7. 因此,我应该能够做到以下几点:

    instance F T1 where
      f1 x = (some function of f2)
    

    或者:

    instance F T1
    instance G T1 where
      g1 x = (some function of g2)
    

    但似乎我能实现这一目标的唯一方法是拥有f1f2的两个默认定义,但我不认为GHC允许这样做。无论如何我可以写这个,这样对于只有类F的类型和类G的类型,只需要实现一个函数吗?

2 个答案:

答案 0 :(得分:1)

如果我得到了正确的要求,他们可以直接满意几个扩展:

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}

class F t where
  f1 :: t -> t -> t
  f1 _ = f2
  f2 :: t -> t
  f2 x = f1 x x

class F t => G t where
  g1 :: t -> t -> t
  g1 x _ = g2 x
  g2 :: t -> t
  g2 x = g1 x x

instance G t => F t where
  f1 = flip g1
  f2 = g2

instance F Int where
  f1 = (-)

main = mapM_ print ([f1 4 2, f2 4] :: [Int])

*Main> :main
2
0

instance可以更改为G

instance G Int where
  g1 = subtract

main = mapM_ print ([f1 4 2, f2 4, g1 4 2, g2 4] :: [Int])

*Main> :main
2
0
-2
0

但是,我认为这个解决方案很差。这种二元性能否以其他方式表达?如果您提供FG的具体示例,则可以找到更合适的设计。

答案 1 :(得分:0)

根据超类来定义子类方法的相当常见的习惯用法(或者是根据子类的超类方法?我永远不能保持直接)是暴露一个显式*Default方法,如< / p>

class F t where
    {-# MINIMAL f1 | f2 #-}
    f1 = ... f2 ...
    f2 = ... f1 ...

f1Default :: G t => ...
f1Default = ... g1 ...

f2Default :: G t => ...
f2Default = ... g2 ...

class G t where
    {-# MINIMAL g1 | g2 #-}
    g1 = ... g2 ...
    g2 = ... g1 ...

这为实例编写器提供了使用默认值的控制。

基础上有很多这种模式的例子,包括fmapDefaultfoldMapDefaultbimapDefaultbifoldMapDefaultmany more,我希望有这个外部基地也有相当多的例子。