2016-12-30 69 views
3

我需要讓GHC知道在類型中使用的值將與函數輸入相同。Haskell斷言類型將與另一個類型匹配

配置定義爲:

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' [email protected]{..} 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功能,我將通過兼容的方式它只知道他們使用了一些相同的類。

+0

難道你不能定義一個Typeclass來定義函數的需求,那麼在函數簽名中包含Typeclass需求? – Carcigenicate

+0

在'runOneTest''中,你可以移動'全部st腳'。 (SysState st,PortIn pin)=>'裏面(st - > Signal pin - > Signal st)'? – danidiaz

回答

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' [email protected]{..} 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!"