考虑以下课程:
class F t where
f1 :: ...
f2 :: ...
class F t => G t where
g1 :: ...
g2 :: ...
我也可以编写以下默认函数:
f1
就f2
而言。f2
就f1
而言。g1
就g2
而言。g2
就g1
而言。f1
就g1
而言G t
。f2
就g2
而言G t
。因此,我应该能够做到以下几点:
instance F T1 where
f1 x = (some function of f2)
或者:
instance F T1
instance G T1 where
g1 x = (some function of g2)
但似乎我能实现这一目标的唯一方法是拥有f1
和f2
的两个默认定义,但我不认为GHC允许这样做。无论如何我可以写这个,这样对于只有类F
的类型和类G
的类型,只需要实现一个函数吗?
答案 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
但是,我认为这个解决方案很差。这种二元性能否以其他方式表达?如果您提供F
和G
的具体示例,则可以找到更合适的设计。
答案 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 ...
这为实例编写器提供了使用默认值的控制。
基础上有很多这种模式的例子,包括fmapDefault
,foldMapDefault
,bimapDefault
,bifoldMapDefault
和many more,我希望有这个外部基地也有相当多的例子。