f#: Tidy same_iterators_p a little.
[fringe] / cl-fringe.lisp
CommitLineData
2bd37ef1
MW
1;;; -*-lisp-*-
2;;;
3;;; Lisp implementation of a `same-fringe' solver.
4
5;;;--------------------------------------------------------------------------
6;;; Iteration utilities.
7
8;; The iteration protocol is as follows. An iterator is simply a function
9;; invoked with no arguments. It returns two values: the next item, and a
10;; new iterator function to produce the remaining items; if there are no more
11;; items, then it returns NIL twice.
12
13(defun list-iterator (iter)
14 "Collect the items from ITER into a list and return it."
15 (labels ((recur (iter list)
16 (multiple-value-bind (data iter) (funcall iter)
17 (if iter
18 (recur iter (cons data list))
19 (nreverse list)))))
20 (recur iter nil)))
21
22(defun same-iterators-p (iter-a iter-b &key (test #'eql))
23 "Return whether ITER-A and ITER-B produce the same items."
24 (labels ((recur (iter-a iter-b)
25 (multiple-value-bind (data-a iter-a) (funcall iter-a)
26 (multiple-value-bind (data-b iter-b) (funcall iter-b)
27 (cond ((null iter-a) (null iter-b))
28 ((or (null iter-b)
29 (not (funcall test data-a data-b)))
30 nil)
31 (t (recur iter-a iter-b)))))))
32 (recur iter-a iter-b)))
33
34;;;--------------------------------------------------------------------------
35;;; Nodes and trees.
36
37(defstruct node
38 "A simple node in a binary tree. Empty subtrees are denoted by NIL."
39 left data right)
40
41(defun iterate-fringe (node)
42 "Inorder iterator for the tree headed by NODE."
43 (labels ((recur (node cont)
44 (cond (node (recur (node-left node)
45 (lambda ()
46 (values (node-data node)
47 (lambda ()
48 (recur (node-right node)
49 cont))))))
50 (cont (funcall cont))
51 (t (values nil nil)))))
52 (lambda () (recur node nil))))
53
54(defun parse-tree (string)
55 "Parse STRING, and return the tree described.
56
57 The syntax is simple:
58
59 tree ::= empty | `(' tree char tree `)'
60
61 The ambiguity is resolved by always treating `(' as a tree when a tree is
62 expected."
63
64 (let ((len (length string)))
65 (labels ((parse (i)
d782cc40 66 (cond ((and (< i len) (char= (char string i) #\())
2bd37ef1
MW
67 (multiple-value-bind (left i) (parse (1+ i))
68 (unless (< i len) (error "no data"))
69 (let ((data (char string i)))
70 (multiple-value-bind (right i) (parse (1+ i))
71 (unless (and (< i len)
72 (char= (char string i) #\)))
73 (error "missing )"))
74 (values
75 (make-node :left left :data data :right right)
76 (1+ i))))))
77 (t (values nil i)))))
78 (multiple-value-bind (tree i) (parse 0)
79 (unless (= i len) (error "trailing junk"))
80 tree))))
81
82;;;--------------------------------------------------------------------------
83;;; Main program.
84
85(defun main (args)
86 "Main program: process ARGS."
87 (destructuring-bind (&optional a b &rest junk) args
88 (cond ((or (null a) junk) (error "bad args"))
89 ((null b) (format t "~{~C~}~%"
90 (list-iterator (iterate-fringe (parse-tree a)))))
91 (t (format t "~:[no match~;match~]~%"
92 (same-iterators-p (iterate-fringe (parse-tree a))
93 (iterate-fringe (parse-tree b))))))))
94
95#+cl-launch
4eee07ac
MW
96(progn
97 (defparameter *program-name*
98 (pathname-name (or (cl-launch:getenv "CL_LAUNCH_FILE")
99 (namestring *load-pathname*)
100 "<unknown>")))
101 (defun launch ()
102 (flet ((bail (format args)
103 (format *error-output* "~A: ~?~%" *program-name* format args)
104 (cl-launch:quit 1)))
105 (handler-case
106 (main cl-launch:*arguments*)
107 (simple-error (err)
108 (bail (simple-condition-format-control err)
109 (simple-condition-format-arguments err)))
110 (error (err)
111 (bail "~A" err))))))
2bd37ef1
MW
112
113;;;----- That's all, folks --------------------------------------------------