如何解决在预定义的访问者模式迭代器中提取/累积结果的“Haskell 方式”
我开始使用 Haskell(来自多年的 C 和 C++)并决定尝试一个小型数据库项目。我将预定义的绑定库用于 C 数据库库 (Database.kyotocabint)。由于使用预定义方法时的效果分离,我正在努力弄清楚如何使用迭代器接口执行任何操作。
test7 = do
db <- openTree "testdatabase/mydb.kct" defaultLoggingOptions (Writer [] [])
let visitor = \k v -> putStr (show k) >> putStr ":" >> putStrLn (show v) >>
return (Left NoOperation)
iterate db visitor False
close db
iterate 和visitor 是由库绑定提供的,相关类型是
iterate :: forall db. WithDB db => db -> VisitorFull -> Writable -> IO ()
visitor :: ByteString -> ByteString -> IO (Either VisitorAction b)
但我不知道如何从迭代器内部提取信息而不是单独处理每个信息 - 例如收集列表中以 'a' 开头的所有键,甚至只计算条目数。
>我是否受到限制,因为 iterate 仅具有 IO () 类型,因此我无法构建副作用并且必须重建它以替换库版本?纸上的状态 monad 似乎解决了这个问题,但访问者类型似乎不允许我在后续访问者调用中保持状态。
马修
编辑 - 非常感谢下面的明确答案,其中 siad 0 它不是 Haskell 方式,但也提供了一个解决方案 - 这个答案让我找到了 Mutable objects,我找到了对选项的清晰解释。
解决方法
很遗憾,kyotocabinet
库似乎不支持您的操作。除了 iterate
,它应该公开一些类似的操作,返回比 IO ()
更复杂的东西,比如 IO a
或 IO [a]
,同时需要更复杂的 visitor
函数。
不过,由于我们在 IO
内部工作,因此有一个解决方法:我们可以利用 IORef
并收集结果。不过,我想强调的是,这不是人们会用 Haskell 编写的惯用代码,但是由于这个库的限制,人们不得不使用一些东西。
无论如何,代码看起来像这样(未经测试):
test7 = do
db <- openTree "testdatabase/mydb.kct" defaultLoggingOptions (Writer [] [])
w <- newIORef [] -- create mutable var,initialize to []
let visitor = \k v -> do
putStrLn (show k ++ ":" ++ show v)
modifyIORef w ((k,v):) -- prepend (k,v) to the list w
return (Left NoOperation)
iterate db visitor False
result <- readIORef w -- get the whole list
print result
close db
由于您来自 C++,您可能想将上面的代码与以下伪 C++ 进行比较:
std::vector<std::pair<int,int>> w;
db.iterate([&](int k,int v) {
std::cout << k << "," << v << "\n";
w.push_back({k,v});
});
// here we can read w,even if db.iterate returns void
再说一次,这不是我认为惯用的 Haskell。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。