如何包装?

时间:2017-09-25 08:26:58

标签: haskell

我有来自haskellbook的以下代码片段,它逐步显示monad变换器将如何解包:

module OuterInner where

  import Control.Monad.Trans.Except
  import Control.Monad.Trans.Maybe
  import Control.Monad.Trans.Reader

  -- We only need to use return once
  -- because it's one big Monad
  embedded :: MaybeT (ExceptT String (ReaderT () IO)) Int
  embedded = return 1

  maybeUnwrap :: ExceptT String (ReaderT () IO) (Maybe Int)
  maybeUnwrap = runMaybeT embedded

  -- Next
  eitherUnwrap :: ReaderT () IO (Either String (Maybe Int))
  eitherUnwrap = runExceptT maybeUnwrap

  -- Lastly
  readerUnwrap :: () -> IO (Either String (Maybe Int))
  readerUnwrap = runReaderT eitherUnwrap

有一项练习,我必须再次包装所有内容:

embedded :: MaybeT (ExceptT String (ReaderT () IO)) Int
embedded = ??? (const (Right (Just 1))) 

我尝试如下:

embedded' :: MaybeT (ExceptT String (ReaderT () IO)) Int
embedded' = MaybeT (ExceptT (ReaderT (const (Right (Just 1)))))

但是编译器抱怨:

D:\haskell\chapter26\src\OuterInner.hs:24:15: error:
    * Couldn't match type `Either a0' with `IO'
      Expected type: MaybeT (ExceptT String (ReaderT () IO)) Int
        Actual type: MaybeT (ExceptT String (ReaderT () (Either a0))) Int
    * In the expression:
        MaybeT (ExceptT (ReaderT (const (Right (Just 1)))))
      In an equation for embedded':
          embedded' = MaybeT (ExceptT (ReaderT (const (Right (Just 1)))))

D:\haskell\chapter26\src\OuterInner.hs:24:32: error:
    * Couldn't match type `Maybe Integer'
                     with `Either String (Maybe Int)'
      Expected type: ReaderT () (Either a0) (Either String (Maybe Int))
        Actual type: ReaderT () (Either a0) (Maybe Integer)
    * In the first argument of `ExceptT', namely
        `(ReaderT (const (Right (Just 1))))'
      In the first argument of `MaybeT', namely
        `(ExceptT (ReaderT (const (Right (Just 1)))))'
      In the expression:
        MaybeT (ExceptT (ReaderT (const (Right (Just 1)))))
Failed, modules loaded: none.

如何解决这个问题?

2 个答案:

答案 0 :(得分:5)

您已定义MaybeT (ExceptT String (Reader ())) Int。你错过了最里层IO。与其他人不同,IO没有具体的表示,但您当然可以使用returnpure(duh)将纯值注入其中。

embedded' = MaybeT . ExceptT . ReaderT
           $ (pure .) . const . Right $ Just 1

答案 1 :(得分:5)

GHC打字延伸救援!它允许你在表达式的某个地方探测_并让GHC告诉你需要的类型。那么,让我们从

开始吧
:t MaybeT (ExceptT (ReaderT (const _)))

<interactive>:1:33: error:
    * Found hole: _ :: m (Either e (Maybe a))

现在我们需要ReaderT () (Either e (Maybe a))的值。管道_一遍又一遍,我们终于达到了价值

embedded = MaybeT (ExceptT (ReaderT (const (return (Right (Just 1))))))