Haskell 断言一个类型将匹配另一个
Haskell assert that a type will match another
我需要让 GHC 知道在类型内部使用的值将与函数输入相同。
配置定义为:
data Config = forall p s . (PortIn p, SysState s, Show p, Show s) =>
Config { input :: p
, startSt :: s
}
它的class是:
class Show t => Transition t where
runOneTest :: forall st pin . (SysState st, PortIn pin)
=> t
-> (st -> Signal pin -> Signal st)
-> Signal TestResult
实例为:
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
我遇到错误:
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
我认为问题是:
GHC 无法知道 startSt 和输入将与我将传入的 topEntity 函数兼容。它只知道它们使用一些相同的 classes。
您的分析是正确的:调用者可以传递一个 Config
值,该值包含 topEntity'
所需的不同类型。
一种选择是避免存在 Config
类型并将其转换为显式
data Config p s = ...
runOneTest' :: forall st pin . (SysState st, PortIn pin)
=> Config pin st
-> (st -> Signal pin -> Signal st)
-> Signal TestResult
...
另一种选择是使用 Data.Typeable
执行运行时类型检查。类似于:
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!"
我需要让 GHC 知道在类型内部使用的值将与函数输入相同。
配置定义为:
data Config = forall p s . (PortIn p, SysState s, Show p, Show s) =>
Config { input :: p
, startSt :: s
}
它的class是:
class Show t => Transition t where
runOneTest :: forall st pin . (SysState st, PortIn pin)
=> t
-> (st -> Signal pin -> Signal st)
-> Signal TestResult
实例为:
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
我遇到错误:
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
我认为问题是: GHC 无法知道 startSt 和输入将与我将传入的 topEntity 函数兼容。它只知道它们使用一些相同的 classes。
您的分析是正确的:调用者可以传递一个 Config
值,该值包含 topEntity'
所需的不同类型。
一种选择是避免存在 Config
类型并将其转换为显式
data Config p s = ...
runOneTest' :: forall st pin . (SysState st, PortIn pin)
=> Config pin st
-> (st -> Signal pin -> Signal st)
-> Signal TestResult
...
另一种选择是使用 Data.Typeable
执行运行时类型检查。类似于:
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!"