2012-04-04 75 views
5

我覺得我失去了單子變壓器的一些基本的瞭解,因爲我發現自己編寫這些代碼:電梯誤差值ErrorT單子轉換

import Control.Monad.Identity 
import Control.Monad.Error 

liftError :: Either String Int -> ErrorT String Identity Int 
liftError x = do case x of 
        Right val -> return val 
        Left err -> throwError err 

gateway :: Bool -> ErrorT String Identity Int 
gateway = liftError . inner 

inner :: Bool -> Either String Int 
inner True = return 5 
inner False = throwError "test" 

雖然這工作,我認爲這可能需要做更多典雅。特別是,我正在尋找替代liftError,我認爲我不應該爲自己定義。

什麼是最直接的方式使gatewayinner一起工作,而不改變它們的類型?

回答

6

如果你只是稍微改變一下這些類型,你根本不需要做任何提升。

{-# LANGUAGE FlexibleContexts #-} 

gateway :: Bool -> ErrorT String Identity Int 
gateway = inner 

inner :: MonadError String m => Bool -> m Int 
inner True = return 5 
inner False = throwError "test" 

MonadError有兩個ErrorTEither實例,所以這種方式,您可以使用inner兩者並用。

+0

好的,所以更具體一些,如果我想離開類型,我必須編寫一個手動提升函數嗎?這只是爲了我的理解。 BTW不幸的是我今天不能投票了:/明天你會得票:) – 2012-04-04 18:13:19

+1

不改變類型,你可以使用'ErrorT。返回'代替你的'liftError'函數。您也可以在內部使用更通用的版本,並且只使用受限制的類型來暴露「inner」的副本。 – hammar 2012-04-04 18:23:57

+0

那'ErrorT。返回「正是我所期待的。正如我所提到的,這與任何真正的代碼無關,我只是想了解monad變換器的概念:) – 2012-04-04 18:25:10