这个simiple纯函数队列是否有效?

时间:2013-07-02 03:51:35

标签: data-structures functional-programming scheme queue purely-functional

我在Lisp(Scheme)中开发了一个纯函数队列,如下所示:

;Internal functions
(define (delay-cons x s)
   (cons x (lambda () s)))
(define (delay-car s)
  (car s))
(define (delay-cdr s)
  ((cdr s)))

(define (delay-append s t)
  (if (null? s)
      t
      (delay-cons (delay-car s) (delay-append (delay-cdr s) t))))

;API
(define (enqueue x q) (delay-append q (delay-cons x empty)))
(define dequeue delay-cdr)
(define peek delay-car)
(define empty '())
(define empty? null?)

delay-cons类似于cons,但它通过将尾部包装在闭包中来暂停对尾部的评估。类似的延迟 - 附加(delay-append s t)通过尾部的递归暂停将t附加到s。

因此,每个enqueue包含一层闭包,使其成为O(1),每个peek只检索一个使其成为O(1)的值,并且每个dequeue检索并评估一个闭包使其成为O(1)。

我在其他地方看不到这个;例如,在Okasaki的Purely Functional Data Structures中,最简单的队列是Banker的队列,它比这复杂得多,并且只有摊销O(1)排队,偷看和出队。这使我怀疑我的推理中存在错误。

这个数据结构是否合理?在某处有参考吗?

编辑: 延迟 - 缺点是在延迟附加中使用的错误;我尝试使用像宏一样的功能(感谢Will Ness)。

我尝试使用

更正它
(define (delay-append s t)
  (if (null? s)
      t
      (cons (delay-car s) (lambda () (delay-append (delay-cdr s) t)))))

但这不适用于API。

1 个答案:

答案 0 :(得分:5)

首先,delay-cons可以是一个功能。它必须是一个宏。 For instance

(define-syntax s-cons
  (syntax-rules ()
    ((s-cons h t) (cons h (lambda () t))))) 

在麻省理工学院计划中工作。

但是你可以使用delay-cons中的delay-append 而不是来解决这个问题:

(define (delay-append s t)
  (if (null? s)
      t
      (cons (delay-car s) (lambda () (delay-append (delay-cdr s) t)))))

所以没关系。

至于复杂性,delay-append并非没有成本。它包裹着原始队列。想象一下,它有30个元素;然后你又一个追加10个。现在,原始文件被包裹在10层delay-append中,必须对其进行导航以获取这30个元素中的每一个(实际上29个,因为头部被拉出到直接car,{{{ 1}})。因此对于delay-append - 附加的,n - 访问的使用模式,它看起来像二次复杂性。

Haskell上下文中关于此问题的经典论文是“Why are difference lists more efficient than regular concatenation?”。您的n类似于“常规连接”:

delay-append

以下是插图:

[]  ++ t = t
s   ++ t = (head s) : ((tail s) ++ t)