我目前有一个如下结构:
class F a where
f :: ...
default f :: (G a...) => ...
f = (some definition in terms of g)
class F a => G a where
g :: ...
default g :: (C a...) => ...
g = (some definition in terms of f)
希望我能用通俗易懂的英语,永远用g
来写f
。我有时可以根据f
来写g
,即当a
满足C
约束时。
我在这里看到的问题是,如果有人写了一个满足C T
的类型T
instance F T
instance G T
这将在运行时编译和循环。虽然两个默认定义都是正确的,但重要的是至少定义一个。
如果f
和g
在同一个类中,我可以用MINIMAL
杂注来解决这个问题,但在本例中它们不是。
同样,将f
和g
放在同一类中似乎是不可能的,因为虽然对于g
的每个定义都有f
的定义,但对于f
的每个定义却没有g
的定义。一种可能性是将g
移动到F
中,但也对其施加C a
约束,但这将阻止我用不满足C a
的任何a
的非默认定义来定义g
。
有什么方法可以重组这件事来解决我面临的困境吗?
我之前的答案是无稽之谈,所以这里有一个(希望)更好的答案。这至少会在编译时给您一个警告。技巧是如果两个a
都有F
和G
的实例,则在类G
中实现f'
或g
,但如果G
的实例不可能,则仅实现f
。
{-# LANGUAGE DefaultSignatures #-}
class C a where
class F a where
f :: a -> a
default f :: (G a) => a -> a
f = g
class F a => G a where
{-# MINIMAL (f'|g) #-}
f' :: a -> a
f' = f
g :: a -> a
default g :: (C a) => a -> a
g = f'
instance F Integer where
f = succ
instance F Int
instance G Int where
g = succ
instance C Float
instance F Float
instance G Float where
f' = succ
-- This will give a compile time warning, but will still
-- loop at runtime:
instance C Double
instance F Double
instance G Double