
Alfonso Acosta wrote: I have a type problem in my code which I dont know how to solve
data HDSignal a = HDSignal class HDPrimType a where class PortIndex a where
class SourcePort s where -- Plug an external signal to the port plugSig :: (HDPrimType a, PortIndex ix) =>ix -> s ->(HDSignal a -> b) -> b
class DestPort d where -- Supply a signal to the port supplySig :: (PortIndex ix, HDPrimType a) => HDSignal a -> ix -> d -> d
-- Connect providing indexes connectIx :: (SourcePort s, PortIndex six, DestPort d, PortIndex dix) => six -> s -> dix -> d -> d connectIx six s dix d = plugSig six s $ (push2 supplySig) dix d
I'm afraid the example may be a bit too simplified. The first question: what is the role of the |HDPrimType a| constraint in plugSig and supplySig? Do the implementations of those functions invoke some methods of the class HDPrimType? Or the |HDPrimType a| constraint is just to declare that the parameter |a| of HDSignal is a member of HDPrimType? If it is the latter, that intention is better declared
data HDPrimType a => HDSignal a = HDSignal
Any function constructing the value HDSignal has to prove to the typechecker that the type |a| satisfied the HDPrimType constraint. Once we ensured that only properly constrained HDSignal can be constructed, the HDPrimType constraint can be removed from the signature of plugSig and supplySig, and the example compiles. It compiles because plugSig requires a supplicant that can process any HDSignal, and supplySig promises to be exactly this supplicant, which is able to process HDSignal without looking at it. With the original HDPrimType constraint, the meaning is the same. Although neither plugSig or supplySig care about which particular instance of HDPrimType is chosen, the typechecker must chose some instance. Alas, there is no information in the signature of connectIx to help the typechecker chose the instance. There is no defaulting. If plugSig and supplySig do use the methods of HDPrimType, one could use existentials:
data HDSignal' = forall a. HDPrimType a => HDSignal' (HDSignal a) class SourcePort s where plugSig :: (PortIndex ix) => ix -> s -> (HDSignal' -> b) -> b
class DestPort d where supplySig :: (PortIndex ix) => HDSignal' -> ix -> d -> d
That works too.