Monad 在从 Lift 移植到 Yesod 的 Persistent 时遇到了麻烦

Posted

技术标签:

【中文标题】Monad 在从 Lift 移植到 Yesod 的 Persistent 时遇到了麻烦【英文标题】:Monad troubles porting from Lift to Yesod's Persistent 【发布时间】:2012-09-27 18:57:51 【问题描述】:

我有一个 Lift 应用程序,我将其移植到 Yesod,作为学习框架和 Haskell 的一种方式。应用程序的一部分仅驻留在 TCP 和数据库层:解析来自套接字连接的传入字节并将它们转换为更新以供模型处理。我在 Scala 中使用正则表达式和模式匹配进行了此操作,但未能在 Haskell 中重现它。

一个高度简化的例子:

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist|
Person
    name String
    deriving Show

UnknownMessage
    text String
    deriving Show
|]

parseMsg m = runDB $ do
    case ms of
        ["add",name]       -> insert PersonpersonName = name
        ["delete",name]    -> deleteWhere [PersonName ==. name]
        ["change",from,to] -> updateWhere [PersonName ==. from] [PersonName =.to]
        _                  -> insert UnknownMessageunknownMessageText = m
where
    ms = splitRegex (mkRegex ",") m

上面的代码只会在四个模式匹配中的三个被注释掉的情况下编译。 "insert Person" 不能与 "deleteWhere" 一起玩,甚至不能与 "insert UnknownMessage" 一起玩。结果往往是类型匹配的错误消息,我经常无法做出正面或反面。

我该如何重写上面的代码?是否有针对任何地方受到单子挑战的持久指南?本书章节没有详细介绍如何链接查询等。

编辑:hammar 将 (>>) 添加到插入内容的建议解决了该问题。如果我删除“runDB $ do”,函数的类型变为“parseMsg :: PersistQuery backend m => String -> backend m ()”。这是否允许我稍后在 monad 中执行返回的查询,就像我在 Scala 中处理我的更新一样?

【问题讨论】:

你能给我们这样的错误信息吗?可能有助于了解正在发生的事情,而无需为我们这些不知道的人弄清楚是什么。 【参考方案1】:

我不是 Yesod 专家,但从快速查看文档看来,问题在于 insert 操作返回新记录的键,而 updateWheredeleteWhere 都返回 @987654325 @。

insert      :: (...) => val -> backend m (Key backend val)
updateWhere :: (...) => [Filter val] -> [Update val] -> backend m ()
deleteWhere :: (...) => [Filter val] -> backend m ()

想必这里的key你并不关心,所以你可以通过做丢弃它

insert PersonpersonName = name >> return ()

应该进行类型检查。

【讨论】:

另见:void 另见:insert_ :: val -> m ()

以上是关于Monad 在从 Lift 移植到 Yesod 的 Persistent 时遇到了麻烦的主要内容,如果未能解决你的问题,请参考以下文章

函数式编程-将Monad(单子)融入Swift

将 Yesod 部署到 Heroku,无法静态构建

当用户不在 Yesod/Haskell 的数据库中时如何重定向到特殊页面

Haskell语言学习笔记(69)Yesod

选择具有 yesod 持久性的列子集

如何让 yesod-persistent 识别我的 aeson 解析实体数组的类型?