Thanks for the reply, Adam!
It looks like the problem is the combination of existentials and overlapping instances (which don't behave sensibly together).
Here's a new version (that also doesn't work!) but that I think is a lot closer -- this one uses type families instead of overlapping instances:
[pragmas [0]]
import Data.Proxy
-- Same as before:
data Fs a c where
F :: (a -> c) -> Fs a c
Compose :: forall a b c. Fs b c -> Fs a b -> Fs a c
class TEq x0 x1 y0 y1 where
isEq :: Fs x0 x1 -> (y0 -> y1) -> String
instance (
flag ~ IEq (Fs x0 x1) (y0 -> y1)
, TEq' x0 x1 y0 y1 flag
) => TEq x0 x1 y0 y1 where
isEq = isEq' (Proxy::Proxy flag)
type family IEq a b :: Bool where
IEq (Fs x0 x1) (xo -> x1) = 'True
IEq a b = 'False
class TEq' x0 x1 y0 y1 (flag :: Bool) where
isEq' :: Proxy flag -> (Fs x0 x1) -> (y0 -> y1) -> String
instance TEq' x0 x1 y0 y1 'True where
isEq' _ _ _ = "yes!"
instance TEq' x0 x1 y0 y1 'False where
isEq' _ (F _) _ = "no"
-- isEq' _ (Compose a b) f = "compose("++isEq a f++", "++isEq b f++")"
The problem is the last line -- the "hidden" type can't be inferred to be in TEq', although every type is in fact in TEq'
Any more help would be very appreciated!
Thanks,
Tom
[0]
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs, NoMonoLocalBinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-} -- new
{-# LANGUAGE TypeFamilies #-} -- new
{-# LANGUAGE UndecidableInstances #-}