2011-12-03 31 views
5

我使用的是Heinrich Apfelmus的operational monad。 我想用monad參數化解釋器的結果類型。 我的代碼以下版本編譯:具有任意單子解釋器的操作monad

{-# LANGUAGE GADTs #-} 

import Control.Monad.Operational 

data EloI a where 
    Display :: Int -> EloI() 

type Elo a = Program EloI a 

interpret :: Monad m => (Int -> m()) 
        -> Elo a 
        -> Int 
        -> m a 
interpret display = interp 
    where 
    interp :: Monad m => Elo a -> Int -> m a 
    interp = eval . view 
    eval :: Monad m => ProgramView EloI a -> Int -> m a 
    eval (Display i :>>= is) s = interp (is()) s 

現在我改變最後一行

eval (Display i :>>= is) s = display i >> interp (is()) s 

和類型推斷不會成功了,我得到的輸出

未能進行從上下文(Monad m)推斷(m〜m1)
受解釋類型簽名的限制:: Monad m =>(Int→m())→Elo a→Int→ma )

當我刪除interp的類型簽名時,我得到一個額外的錯誤(無法推斷(a1〜a))。
當我將所有m更改爲IO(例如操作monad的tic tac腳趾示例)時,它會再次編譯。
我在嘗試一些沒有道理的事情,或者我可以向GHC提供一些提示嗎?我不得不承認我不確定我需要這種靈活性。

回答

8

這是因爲本地類型簽名中的m是新鮮類型變量,所以他們承諾可以使用任何 Monad。如果您使用display,則eval只能用於特定monad display的用途。它應該工作,如果你一)刪除本地類型簽名,或b)把類型變量m到範圍

{-# LANGUAGE ScopedTypeVariables #-} 
... 
interpret :: forall m. (Int -> m()) -> Elo a -> Int -> m a 
+0

我甚至沒有嘗試)(althaugh我通常不使用本地類型簽名),因爲示例代碼中的以下語句「請注意,由於ProgramView是GADT,因此eval的類型註釋是強制性的。」 – Duschvorhang