File: delayed.lisp

package info (click to toggle)
cl-rsm-delayed 1.1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k, sarge
  • size: 72 kB
  • ctags: 30
  • sloc: lisp: 495; makefile: 44; sh: 28
file content (210 lines) | stat: -rw-r--r-- 7,184 bytes parent folder | download | duplicates (2)
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          delayed.lisp
;;;; Purpose:       Manipulate delayed lists.
;;;; Author:        R. Scott McIntire
;;;; Date Started:  Aug 2003
;;;;
;;;; $Id: delayed.lisp,v 1.2 2003/08/21 19:57:11 kevinrosenberg Exp $
;;;; *************************************************************************

(in-package rsm.delayed)

(eval-when (:compile-toplevel)
  (declaim (optimize (speed 3) (debug 0) (safety 1) (space 0))))


(defmacro cons (first &body body)
  "A delayed \"cons\"."
  `(cl:cons ,first #'(lambda () ,@body)))

(defmacro list (&rest elems)
  "A delayed \"list\"."
  `(when ',elems
     (reduce #'(lambda (x y) (cons x y)) ',elems
             :initial-value nil :from-end t)))


(defun delayed-p (stream)
  "Predicate that determines if <stream> is a delayed list."
  (and (consp stream)
       (functionp (cl:cdr stream))))

(deftype delayed ()
  "Type for a delayed list."
  '(satisfies delayed-p))


(defun car (stream)
  "The \"car\" for a delayed list; it is identical to cl:car when <stream> is an
ordinary list."
  (cl:car stream))

(defun cdr (stream)
  "The \"cdr\" for a delayed list; it is identical to cl:cdr when <stream> is an
ordinary list."
  (if (delayed-p stream)
      (funcall (cl:cdr stream))
    (cl:cdr stream)))


(defun nth (n stream)
  "Nth for delayed lists. Works when <stream> is an ordinary list."
  (cond ((delayed-p stream)
         (cond ((= n 0)
                (car stream))
               ((> n 0)
                (let ((st stream))
                  (loop
                    :repeat n :do
                    (setf st (cdr st))
                    (when (null st)
                        (return-from nth nil)))
                  (car st)))
               (t
                (error "delayed:nth: invalid first argument, ~s~%" n))))
        ((listp stream)
         (if (and (integerp n)
                  (>= n 0))
             (cl:nth n stream)
           (error "delayed:nth: invalid first argument, ~s~%" n)))
        (t
         (error "delayed:nth: Bad arguments."))))


(defun take (n stream)
  "Take the first <n> elements from <stream>, returning them as a list.  Works
when <stream> is an ordinary list."
  (if (not (delayed-p stream))
      (let ((st stream)
            (result (rsm.queue:create)))
        (when (> n 0)
          (loop
            :repeat n :do
            (rsm.queue:enqueue (cl:car st) result)
            (when (null (cl:cdr st))
              (return-from take (rsm.queue:nget-list result)))
            (setf st (cl:cdr st)))
          (rsm.queue:nget-list result)))
    (do ((cur stream (cdr cur))
         (count 0 (1+ count))
         (result (rsm.queue:create)))
        ((= count n) (rsm.queue:nget-list result))
      (if (null cur)
          (return-from take (rsm.queue:nget-list result))
        (rsm.queue:enqueue (car cur) result)))))

(defun drop (n stream)
  "Drop the first <n> elements from <stream>, return the resulting (possibly
delayed) list. Will work when <stream> is an ordinary lists as well.  In this
case the result is an ordinary list."
  (if (not (delayed-p stream))
      (let ((st stream))
        (when (> n 0)
          (loop
            :repeat n :do
            (when (not (cdr st))
              (return-from drop nil))
            (setf st (cdr st)))
          st))
    (let ((cur stream))
      (loop :repeat n :do
        (setf cur (cdr cur))
        (when (null cur)
          (return-from drop nil)))
      cur)))


(defun repeat (x)
  "Repeat x indefinitely."
  (cons x (repeat x)))

(defun cycle (list)
  "Repeat the list, <list>, indefinitely."
  (reduce #'(lambda (x y)
              (cons x y)) (butlast list)
              :from-end t :initial-value (cons (cl:car (last list))
                                               (cycle list))))


(defun zip-with (s1 s2 &optional (zip-func #'cl:cons))
  "A Lisp version of Haskell's zipWith function. Will work with mixtures of
ordinary lists and delayed lists."
  (cond ((or (null s1) (null s2))
         nil)
        ((and (delayed-p s1)
              (delayed-p s2))
         (let ((e1 (car s1))
               (e2 (car s2)))
           (cons (funcall zip-func e1 e2)
                 (zip-with (cdr s1) (cdr s2) zip-func))))
        ((and (listp s1)
              (delayed-p s2))
         (do ((cur1 s1 (cl:cdr cur1))
              (cur2 s2 (cdr cur2))
              (result (rsm.queue:create)))
             ((or (null cur1) (null cur2)) (rsm.queue:nget-list result))
           (rsm.queue:enqueue (funcall zip-func (cl:car cur1) (car cur2)) 
                              result)))
        ((and (listp s2)
              (delayed-p s1))
         (do ((cur1 s1 (cdr cur1))
              (cur2 s2 (cl:cdr cur2))
              (result (rsm.queue:create)))
             ((or (null cur2) (null cur1)) (rsm.queue:nget-list result))
           (rsm.queue:enqueue (funcall zip-func (car cur1) (cl:car cur2)) 
                              result)))
        ((and (listp s1)
              (listp s2))
         (do ((cur1 s1 (cl:cdr cur1))
              (cur2 s2 (cl:cdr cur2))
              (result (rsm.queue:create)))
             ((or (null cur1) (null cur2)) (rsm.queue:nget-list result))
           (rsm.queue:enqueue (funcall zip-func (cl:car cur1) (cl:car cur2)) 
                              result)))
        (t
         (error "delayed:zip-with: One or more arguments are either not a list 
or not a delayed list."))))



(defun mapcar (func &rest streams)
  "Mapcar for delayed lists. However, will work with a mixture of delayed lists
and ordinary lists."
  (if (some #'null streams)
      nil
    (cond ((every #'delayed-p streams)
           (let ((args (rsm.queue:create)))
             (dolist (stream streams)
               (rsm.queue:enqueue (car stream) args))
             (cons (apply func (rsm.queue:nget-list args))
                   (apply #'mapcar func (cl:mapcar #'cdr streams)))))
          ((and (every #'listp streams)
                (some #'(lambda (stream)
                          (not (delayed-p stream))) streams))
           (let ((args (rsm.queue:create)))
             (dolist (stream streams)
               (if (null stream)
                   (return-from mapcar nil)
                 (rsm.queue:enqueue (car stream) args)))
             (cl:cons (apply func (rsm.queue:nget-list args))
                      (apply #'mapcar func (cl:mapcar #'cdr streams)))))
          ((every #'listp streams)
           (apply #'cl:mapcar func streams))
          (t
           (error "delayed:mapcar: One or more of the arguments is not a list 
or not a delayed list. Check the order of the arguments.")))))
  

(defun filter (stream pruner)
  "Filter a stream (or an ordinary list) by excluding elements that satisfy
<pruner>. If <stream> is an ordinary list an ordinary list is returned."
  (if (delayed-p stream)
      (let ((c (car stream)))
        (if (funcall pruner c)
            (filter (cdr stream) pruner)
          (cons c (filter (cdr stream) pruner))))
    (rsm.filter:filter stream pruner)))