我对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。我怎么能做到这一点?
提前致谢。
答案 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“弄脏”的所有代码必须保持在一起。因此,通常您希望最小化“不纯”的代码,而是专注于编写纯函数并在不纯的计算中使用它们。