如何在Haskell中懒惰地加载Lists以外的数据类型

时间:2011-09-29 03:11:15

标签: haskell graph

我开始理解Haskell的强大功能以及如何以诸如

之类的方式利用延迟加载
main = do
  s <- getContents
  let r = map processIt (lines s)
  putStr (unlines r)

但是我遇到的麻烦是扩展这种“先在数据结构中说什么,但在需要时获取它”的功能,用于其他数据类型。

例如,我有一个图表类型。

type Key = String
data Node = Node { key :: Key, links :: [Node] }

我想编写一个纯粹的代码,这个代码可以作用于这个图形(Strait正向搜索算法),无论它是如何构建的,但是当我到达它们时,我希望节点能够懒洋洋地填充它们。

我认为我需要一种方法来预先指定图中的内容以及如何填充它(某种递归定义)但我很难看到如何。 像

这样的东西
loadGraph :: Key -> Node
loadGraph k =
  let (key,edges) = getNodeAndEdgesFromInternetOrDatabase k in
  Node key (map loadGraph edges)

我觉得这很接近,但我不太清楚该怎么做。帮助和提示将不胜感激。 (特别是像getNodeAndEdgesFromInternetOrDatabase类型的东西)

1 个答案:

答案 0 :(得分:3)

懒惰IO通常使用unsafeInterleaveIO实现,这会延迟IO操作的副作用,直到需要它的结果。

对于你的例子,它会是这样的。

loadGraph :: Key -> IO Node
loadGraph k = unsafeInterleaveIO $ do
  (key, edges) <- getNodeAndEdgesFromInternetOrDatabase k
  edges' <- mapM loadGraph edges
  return (Node key edges')

由于unsafeInterleaveIO正在包含对loadGraph的每次调用,因此当您尝试对其进行评估时,这只会加载该子图。

某些人不喜欢懒惰的IO,因为它很难推断副作用发生的顺序。但是,我认为对于您的应用程序而言,它可能是合适的,只要您在实施getNodeAndEdgesFromInternetOrDatabase的方式时要小心。