Haskell'拆包'monad

时间:2013-10-30 22:53:08

标签: haskell monads yesod

我对Haskell中的monad没有很好的掌握,我无法弄清楚如何解决这个问题。

以下一段代码包含在do语句中。

(...)
x <- runDB $ do
    receipts <- selectList [] []
    users <- selectList [] []
    receiptUsers <- selectList [] []
    return $ joinTables3 receiptUserUserId receiptUserReceiptId receiptUsers users receipts
let allUsers = runDB $ do 
    receipts <- selectList [] []
    users <- selectList [] []
    receiptUsers <- selectList [] []
    return $ joinTables3 receiptUserUserId receiptUserReceiptId receiptUsers users receipts

let answer = functionUsingValue x --functionUsingValue allUsers
(...)

不清楚每个变量在这里是什么,但我希望这对我的问题不是问题。

我的目标是创建一个函数,它返回与x中存储的值完全相同的值,但我现在所拥有的函数不正确,而是函数返回一个monad。我怎么能做到这一点?

提前致谢。

1 个答案:

答案 0 :(得分:2)

我做了一些挖掘,答案是......不。 runDB在Yesod的GHandler monad中吐出一个结果。但是,这个monad实际上是几个monad的组合,包括IO

类型IO a -> a的任何函数在Haskell中都是非常不安全的,因为无法保证何时或甚至IO monad中出现的副作用都会运行!由于GHandler包含IO,因此您无法运行它,这样做意味着您可以像这样派生IO a -> a类型的内容

uhoh :: IO a -> a
uhoh = runGHandler . liftIO

因此,如果您想在纯代码中使用x,那么要点是您编写纯代码

foo :: a -> b

然后你在代码中使用它

myHandler = do
  x <- runDB $ ...
  let x' = foo x
  saveTheWorldWith x'

但是你的monad“弄脏”的所有代码必须保持在一起。因此,通常您希望最小化“不纯”的代码,而是专注于编写纯函数并在不纯的计算中使用它们。