Reputation: 435
I need to let GHC know that the value being use inside of a type will be the same as a functions inputs.
Config is defined as :
data Config = forall p s . (PortIn p, SysState s, Show p, Show s) =>
Config { input :: p
, startSt :: s
}
Its class is:
class Show t => Transition t where
runOneTest :: forall st pin . (SysState st, PortIn pin)
=> t
-> (st -> Signal pin -> Signal st)
-> Signal TestResult
The instance is:
instance Transition Config where
runOneTest = runOneTest'
runOneTest' :: forall st pin . (SysState st, PortIn pin)
=> Config
-> (st -> Signal pin -> Signal st)
-> Signal TestResult
runOneTest' config@Config{..} topEntity' = TestResult config <$> result
where
result = topEntity' startingState inputSignal
startingState = startSt
inputSignal = signal input
I am getting the errors:
Couldn't match expected type `st' with actual type `s'
`s' is a rigid type variable bound by
a pattern with constructor
Config :: forall p s.
(PortIn p, SysState s, Show p, Show s) =>
p -> s -> Config,
in an equation for runOneTest'
at ConvertedClashExamples\TestProc.hs:61:20
`st' is a rigid type variable bound by
the type signature for
runOneTest' :: (SysState st, PortIn pin) =>
Config -> (st -> Signal pin -> Signal st) -> Signal TestResult
at ConvertedClashExamples\TestProc.hs:57:23
Relevant bindings include
result :: Signal st (bound at ConvertedClashExamples\TestProc.hs:63:5)
startingState :: s (bound at ConvertedClashExamples\TestProc.hs:64:5)
topEntity' :: st -> Signal pin -> Signal st (bound at ConvertedClashExamples\TestProc.hs:61:31)
startSt :: s (bound at ConvertedClashExamples\TestProc.hs:61:20)
runOneTest' :: Config
-> (st -> Signal pin -> Signal st) -> Signal TestResult
(bound at ConvertedClashExamples\TestProc.hs:61:1)
In the first argument of topEntity', namely `startingState'
In the expression: topEntity' startingState inputSignal
What I think the problem is: GHC has no way of knowing that the startSt and input are going to be compatible with the topEntity function I will be passing in. It just knows that they use some of the same classes.
Upvotes: 3
Views: 502
Reputation: 116139
Your analysis is right on the spot: the caller can pass a Config
value which carries different types of those required by topEntity'
.
One option is to avoid the existential Config
type and turn it into an explicit one
data Config p s = ...
runOneTest' :: forall st pin . (SysState st, PortIn pin)
=> Config pin st
-> (st -> Signal pin -> Signal st)
-> Signal TestResult
...
Another option is to perform a runtime type check using Data.Typeable
. Something like:
import Data.Typeable
data Config = forall p s . (PortIn p, SysState s, Show p, Show s, Typeable s) =>
Config { input :: p
, startSt :: s
}
runOneTest' :: forall st pin . (SysState st, PortIn pin)
=> Config
-> (st -> Signal pin -> Signal st)
-> Signal TestResult
runOneTest' config@Config{..} topEntity' = TestResult config <$> result
where
result = topEntity' startingState inputSignal
startingState = startSt
inputSignal = signal input2
input2 = case cast input :: st of
Just i -> i
Nothing -> error "wrong runtime type!"
Upvotes: 3