1

我正试图让我的 MongoDB 在 Haskell 中工作。我以本教程为起点。当我在前奏中执行这些命令时,我会得到一个集合列表:

pipe <- runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
access pipe master <databaseName> $ auth <username> <password>
access pipe master <databaseName> allCollections

但是,当我尝试将其放入 Yesod Handler 时,它并没有编译。我有

getActivityR :: Handler Import.Value
getActivityR = do
    pipe <- runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
    access pipe master <databaseName> $ auth <username> <password>
    access pipe master <databaseName> allCollections
    returnJson $ object ["activity" .= ("abc" :: Text)]

returnJson 真的只是让我知道我完成了该方法。最终它将返回活动列表。

我得到的错误是:

Couldn't match type `IO' with `HandlerT App IO'

    Expected type: HandlerT App IO Pipe

      Actual type: IO Pipe

    In a stmt of a 'do' block:

      pipe <- runIOE

              $ connect $ Host "XXXXXX.mongolab.com" $ PortNumber 33317

那么 Prelude/GHCi 和我的由 Cabal 构建的 Yesod 代码有什么区别?

4

1 回答 1

3

问题是 GHCi 在 monad 中运行您的代码IO,而您的函数在HandlerT App IOmonad 中。但是HandlerT是 monad 之上的一个 monad 转换IO器,所以你可以用它lift来“提升”你的IO动作到一个HandlerT App IO动作。电梯的类型是:

lift :: (MonadTrans t, Monad m) => m a -> t m a

在您的情况下,t必须是HandlerT App并且m必须是IO。所以正确的代码如下所示:

getActivityR :: Handler Import.Value
getActivityR = do
    pipe <- lift $ runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317
    access pipe master <databaseName> $ auth <username> <password>
    access pipe master <databaseName> allCollections
    returnJson $ object ["activity" .= ("abc" :: Text)]

我不知道你access是什么,所以我不知道你是否也需要那里的电梯。

对于您的特殊情况,还有liftIOwhich is like lift,但会直接提升到 IO,而不仅仅是提升到 monad 转换器堆栈中的下一个“层”,因此您应该使用它:

pipe <- liftIO $ runIOE $ connect $ Host "XXXXX.mongolab.com" $ PortNumber 33317

如果您想了解有关此主题的更多信息,您应该查找“monad 转换器”。

于 2013-07-02T18:54:25.257 回答