Haskell断言一个类型会匹配另一个类型

时间:2016-12-30 22:02:30

标签: haskell ghc

我需要让GHC知道在类型中使用的值将与函数输入相同。

配置定义为:

data Config = forall p s . (PortIn p, SysState s, Show p, Show s) =>
              Config { input   :: p
                     , startSt :: s
                     }

它的课程是:

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和input将与我将传入的topEntity函数兼容。它只知道它们使用了一些相同的类。

1 个答案:

答案 0 :(得分:3)

您的分析是正确的:调用者可以传递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!"