Preventing mutually recursive default methods during runtime looping

I currently have a structure similar to the following:

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)

Hoping for some simple English, I can always write fin terms g. Sometimes I can write gin terms f, namely when it asatisfies the condition C.

The problem I see here is if someone writes, for example, a type TsatisfyingC T

instance F T
instance G T

This will compile and loop at runtime. Although both definitions are correct by default, it is important to define at least one.

I could solve this by using MINIMALa pragma if fand gwere in the same class, but in this case they are not.

f, g , g f, g f. g f, C a, g a, C a.

, , ?

+6
1

, () . , , . Trick f' g g, a F g, 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
0

All Articles