我正在编写一个试图实现玩具XML处理器的程序.现在,程序应该读取描述文档结构的事件流(想想SAX)并且懒惰地构建相应的树.
事件由以下数据类型定义:
data Event = Open String
| Close
Run Code Online (Sandbox Code Playgroud)
那么可能的输入是:
[Open "a", Open "b", Close, Open "c", Close, Close]
Run Code Online (Sandbox Code Playgroud)
这将对应于树:
a
/ \
b c
Run Code Online (Sandbox Code Playgroud)
我想以懒惰的方式生成树,因此它不需要在任何时候以完整的形式存在于内存中.但是,我当前的实现似乎存在空间泄漏,导致所有节点即使在不再需要时也会被保留.这是代码:
data Event = Open String
| Close
data Tree a = Tree a (Trees a)
type Trees a = [Tree a]
data Node = Node String
trees [] = []
trees (Open x : es) =
let (children, rest) = splitStream es
in (Tree (Node x) (trees children)) : (trees rest)
splitStream es = …Run Code Online (Sandbox Code Playgroud) 我正在编写各种数据库库.它导出的基本功能如下:
withDatabase :: FilePath -> (DBHandle -> IO a) -> IO a
Run Code Online (Sandbox Code Playgroud)
它自动管理数据库句柄的生命周期.
在内部,withDatabase使用Control.Exception中的bracket函数.
withDatabase path f = bracket (openDatabase path) closeDatabase f
Run Code Online (Sandbox Code Playgroud)
在我的具体情况下,openDatabase可能会执行一些重要的I/O,因此会长时间阻塞.出于这个原因,我想运行它的一部分异步异常unmasked.(简化)实施可以是:
openDatabase :: FilePath -> IO DBHandle
openDatabase path = mask $ \restore -> do
h <- openFile path ReadWriteMode
restore (doLongStuff h) `onException` (hClose h)
...
return (DBHandle h)
Run Code Online (Sandbox Code Playgroud)
我不确定这段代码是否产生了我想要的效果.
让我们回顾一下withDatabase,这次取代bracket它的定义:
withDatabase path f = mask $ \restore -> do
h <- openDatabase path …Run Code Online (Sandbox Code Playgroud)