-
Notifications
You must be signed in to change notification settings - Fork 16
/
queues.sls
135 lines (117 loc) · 3.67 KB
/
queues.sls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!r6rs
;;; queues.sls --- Purely functional queues
;; Copyright (C) 2011,2012 Ian Price <ianprice90@googlemail.com>
;; Author: Ian Price <ianprice90@googlemail.com>
;; This program is free software, you can redistribute it and/or
;; modify it under the terms of the new-style BSD license.
;; You should have received a copy of the BSD license along with this
;; program. If not, see <http://www.debian.org/misc/bsd.license>.
;;; Commentary:
;;
;; A scheme translation of "Simple and Efficient Purely Functional
;; Queues and Deques" by Chris Okazaki
;;
;;
;;; Documentation:
;;
;; make-queue : () -> queue
;; returns a queue containing no items
;;
;; queue? : any -> boolean
;; tests if an object is a queue
;;
;; queue-length : queue -> non-negative integer
;; returns the number of items in the queue
;;
;; queue-empty? : queue -> boolean
;; returns true if there are no items in the queue, false otherwise
;;
;; enqueue : queue any -> queue
;; returns a new queue with the enqueued item at the end
;;
;; dequeue : queue -> value queue
;; returns two values, the item at the front of the queue, and a new
;; queue containing the all the other items
;; raises a &queue-empty condition if the queue is empty
;;
;; queue-empty-condition? : object -> boolean
;; tests if an object is a &queue-empty condition
;;
;; queue->list : queue -> listof(any)
;; returns a queue containing all the items in the list. The order of
;; the elements in the queue is the same as the order of the elements
;; in the list.
;;
;; list->queue : listof(any) -> queue
;; returns a list containing all the items in the queue. The order of
;; the items in the list is the same as the order in the queue.
;; For any list l, (equal? (queue->list (list->queue l)) l) is #t.
;;
(library (pfds queues)
(export make-queue
queue?
queue-length
queue-empty?
enqueue
dequeue
queue-empty-condition?
list->queue
queue->list
)
(import (except (rnrs) cons*)
(pfds private lazy-lists)
(pfds queues private condition)
(rnrs r5rs))
(define (rotate l r a)
(if (empty? l)
(cons* (head r) a)
(cons* (head l)
(rotate (tail l)
(tail r)
(cons* (head r) a)))))
;;; Implementation
(define-record-type (queue %make-queue queue?)
(fields
(immutable length)
(immutable l)
(immutable r)
(immutable l^)))
(define (make-queue)
(%make-queue 0 '() '() '()))
(define (enqueue queue item)
(let ((len (queue-length queue))
(l (queue-l queue))
(r (queue-r queue))
(l^ (queue-l^ queue)))
(makeq (+ len 1) l (cons* item r) l^)))
(define (dequeue queue)
(when (queue-empty? queue)
;; (error 'dequeue "Can't dequeue empty queue")
(raise (condition
(make-queue-empty-condition)
(make-who-condition 'dequeue)
(make-message-condition "There are no elements to dequeue")
(make-irritants-condition (list queue)))))
(let ((len (queue-length queue))
(l (queue-l queue))
(r (queue-r queue))
(l^ (queue-l^ queue)))
(values (head l)
(makeq (- len 1) (tail l) r l^))))
(define (makeq length l r l^)
(if (empty? l^)
(let ((l* (rotate l r '())))
(%make-queue length l* '() l*))
(%make-queue length l r (tail l^))))
(define (queue-empty? queue)
(zero? (queue-length queue)))
(define (list->queue list)
(fold-left enqueue (make-queue) list))
(define (queue->list queue)
(let loop ((rev-list '()) (queue queue))
(if (queue-empty? queue)
(reverse rev-list)
(let-values (((val queue) (dequeue queue)))
(loop (cons val rev-list)
queue)))))
)