2017-10-09 74 views
6

循环,我现在有像下面这样的结构:防止相互递归默认的方法在运行时

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约束。

我在这里看到的问题是,如果有人写,对于说类型T满足C T

instance F T 
instance G T 

这将在运行时编译和循环。虽然两个默认定义都是正确的,但重要的是至少定义一个。

如果fg在同一个类中,我可以用MINIMAL编译指令解决这个问题,但在这种情况下它们不是。

而且把两者fg在同一类似乎并不可能,因为虽然有针对g每一个定义的f定义,没有为f每一个定义的g定义。一种可能性是将g转换为F,但同时也对其设置了约束条件,但这会阻止我为任何不符合C aa定义g,其中非默认定义为a

有没有办法重组这个来解决我面临的困境?

+1

另一种退而求其次的选择会不会有g'和/或'F'的'默认定义,但是,而不是提供一个实例,作家可以用它来显式的指定选入到一个独立的函数“默认”实现(通过编写'g = defaultG')。希望至少让它有点难以忽略,因为至少有一个是故意的选择。 – Ben

回答

0

我以前的回答是无稽之谈,所以相反,这是一个(希望)更好的。这至少会在编译时给你一个警告。技巧是实现f'gG如果两个a都有FG的实例,但只有f如果G的实例是不可能的。

{-# 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