懒惰与急切的评估和双链表建设

时间:2012-02-14 12:51:50

标签: list haskell lazy-evaluation eager

我睡不着觉! :)

我在Haskell编写了一个构建双链表的小程序。基本语言的属性是懒惰的评估(参见下面的一堆代码)。我的问题是,我是否可以使用纯粹的功能语言执行相同的 eager 评估?在任何情况下,什么属性渴望功能语言必须能够构建这样的结构(杂质?)?

import Data.List

data DLList a = DLNull |
    DLNode { prev :: DLList a
           , x :: a
           , next :: DLList a
           }
  deriving (Show)

walkDLList :: (DLList a -> DLList a) -> DLList a -> [a]
walkDLList _ DLNull = []
walkDLList f n@(DLNode _ x _)  = x : walkDLList f (f n)

-- Returns first and last items.
makeDLList :: [a] -> (DLList a, DLList a)
makeDLList xs = let (first, last) = step DLNull xs in (first, last)
  where
    step prev [] = (DLNull, prev)
                         -- Here I use laziness. 'next' is not built yet, it's a thunk.
    step prev (x : xs) = let this = DLNode prev x next 
                             (next, last) = step this xs
                         in (this, last)

testList :: [Int] -> IO ()
testList l = let
    (first, last) = makeDLList l
    byNext = walkDLList next first
    byPrev = walkDLList prev last
  in do
    putStrLn $ "Testing: " ++ show l
    print byNext
    print byPrev

main = do
  testList []
  testList [1, 2, 3, 4]

3 个答案:

答案 0 :(得分:6)

双向链表可以用纯粹的功能方式在单一链表上以zipper的热切语言实现。例如,请参阅Rosetta Code > Doubly-linked list > OCaml > Functional

答案 1 :(得分:4)

只要语言有闭包,lambdas等等,你就可以随时模拟懒惰。您甚至可以在Java中重写该代码(不改变变量等),您只需将每个“懒惰”操作包装在类似

的操作中
interface Thunk<A> {
   A eval();  
}

当然这看起来很糟糕,但有可能。

答案 2 :(得分:4)

在Prolog的非回溯子集中,可以看作显式设置一次渴望纯函数式语言,您可以轻松地构建双向链表。这是参考透明度使Haskell变得困难,因为它禁止Prolog明确设置名为,显式尚未设置逻辑变量,而是强制Haskell以“扭结”的扭曲方式达到同样的效果。我认为。

另外,在惰性评估下的Haskell的保护递归与在尾递归模式缺点时尚中构建的Prolog的开放式列表之间确实没有太大区别。 IMO。以下是lazy lists in Prolog的示例。 memoized共享存储用作通用访问中介,因此可以安排先前计算的结果进行缓存。

想想看,你可以以限制性的方式使用C作为一种渴望的纯函数式语言,如果你从未重置任何变量,也不能重置任何指针。你仍然有空指针,就像Prolog有变量一样,所以它也是,显式设置一次。当然,您可以使用它构建双向链表。

所以剩下的唯一问题是,您是否承认 set-once 语言为 pure