5

这是一个可能与IO()单子有关的 Haskell 新手问题。

我在一个Happstack.Server程序中有一个函数可以为文件上传生成响应。

postFile = do methodM POST
              decodeBody filePolicy
              (tmp, name, meta) <- lookFile "upload"
              ok $ concat ["A file! ", tmp, " || ", name, " || ", show meta]

这很好用。现在,我希望它显示上传文件的内容以及它的本地临时名称、原始名称和内容类型元数据。我假设既然这一切都发生在一个do街区里,我可以

postFile = do methodM POST
              decodeBody filePolicy
              (tmp, name, meta) <- lookFile "upload"
              contents <- readFile tmp
              ok $ concat ["A file! ", tmp, " || ", name, " || ", show meta, "\n\n", contents]

但这给我带来了一系列错误,似乎告诉我decodeBody电话有问题。

...
/home/inaimathi/projects/happstack-tutorial/parameters.hs:23:15:
    No instance for (Happstack.Server.Internal.Monads.WebMonad
                       Response IO)
      arising from a use of `decodeBody'
    Possible fix:
      add an instance declaration for
      (Happstack.Server.Internal.Monads.WebMonad Response IO)
    In a stmt of a 'do' block: decodeBody filePolicy
    In the expression:
      do { methodM POST;
           decodeBody filePolicy;
           (tmp, name, meta) <- lookFile "upload";
           contents <- readFile tmp;
           .... }
    In an equation for `postFile':
        postFile
          = do { methodM POST;
                 decodeBody filePolicy;
                 (tmp, name, meta) <- lookFile "upload";
                 .... }
...

我不确定这里出了什么问题。有人可以教育我吗?


编辑3:

这将让我学会贸然下结论。

我得到的其他错误都是由于安装不正确的库造成的。清除我的~/.ghc,然后happstack再次安装修复它。

4

1 回答 1

12
No instance for (Happstack.Server.Internal.Monads.WebMonad
                       Response IO)

翻译:您的do-block 不是 IO monad,而是其他一些 monad。幸运的是,它原来是 MonadIO 的一个实例:

class Monad m => MonadIO m where
    liftIO :: IO a -> m a

如您所见,这样的实例只是提供了一种将 IO 操作从 IO 单子“提升”到自身的方法,因此在您的情况下,您只需要:

contents <- liftIO $ readFile tmp

的实现liftIO显然依赖于m,但在一个典型的 monad 转换器堆栈中,它使用liftliftIO到达内部的 IO monad;例如,参见Transformers 库中其他 monad 转换器的实现

于 2012-11-02T05:01:32.443 回答