gpt4 book ai didi

haskell - 在一个事务中执行多个查询

转载 作者:行者123 更新时间:2023-12-03 15:11:36 25 4
gpt4 key购买 nike

我正在移植一个解析器 + SQLite 数据导入器作为我在 Haskell 中的第一个项目,我需要一些帮助来了解一个人应该如何做单子(monad)。
我将 parsec 用于解析部分,然后使用转换函数来排除 SQLite 查询,这些查询将完成将数据插入数据库的工作。

现在,由于它使用了 parsec 解析器,结果数据的类型是:

IO (Either ParseError [(String, [SqlValue])])

这是数据样本
Right ("INSERT OR REPLACE INTO utterances 
(id,name,filelength,updated_at,checksum_algorithm, checksum) VALUES (ifnull(NULL,
(select id from utterances where name = ?)) , ? ,?, datetime(),'MD5',?);",[SqlString
"testdata/testdata.TextGrid",SqlString "testdata/testdata.TextGrid",SqlDouble
1.0,SqlString "FAKE"])

现在,我需要在单个事务中运行查询,但是当数据在 IO (Either x a)) 包中时,我该怎么做呢?

就像我说的,我对 Haskell 很陌生,所以我很感谢我能在这里得到的所有帮助

最佳答案

monad 的“诀窍”是让每个操作尽可能深入地存在于计算中。例如,假设我们有

result :: IO (Either ParseError [(String, [SqlValue])])

然后我们可以写
liftM go result

这样 go只需要处理 Either ParseError [(String, [SqlValue])] 类型的东西并且可以忽略 IO .我们可以更深入。
liftM (liftM makeQuery) result

将是我们可以放置 makeQuery :: [(String, [SqlValue])] -> SqlQuery 的地方创建我们要发送到数据库的查询的构建器。这是一个纯函数,很容易单独测试,比如在我们构建 [(String, [SqlValue])] 的单元测试中。用手一点点。

我们可以通过展开在层之间移动。每个单子(monad)层都有自己的展开方式。例如,我们可以打开 Either通过匹配 case
do either <- result   -- use do notation to look inside of the IO layer
case either of
Left parseError -> putStrLn (show parseError) -- convert the error to some IO
Right insides -> sendQuery db (makeQuery insides) -- send our built query

同样,通过深入 Monad 的内层,我们可以编写更简单的函数。例如,这里虚构的 sendQuery有类型 DBConnection -> SqlQuery -> IO () ,即它只发送 SqlQueries但是他们可能会到达。这具有很强的单一职责原则设计。

在你为自己设定的目标中还有很多复杂性,但处理 monad 本质上归结为这两个工具——分层工作并隔离你的操作。我会尝试构建以下函数:(1) 执行 SQL 数据库操作并将其包装在事务中(该类型可能类似于 withTransaction :: IO () -> IO (),因为它将 IO 操作升级到事务内)(2) 构建查询喜欢 makeQuery上面 (3) 是否像我对 show parseError 所做的那样优雅地处理错误?尽管这显然是一个 hacky 解决方案,并且 (4) 将您的解析隔离到一个地方。

关于haskell - 在一个事务中执行多个查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18037931/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com