From 4d3c19fa977602c9f1465d02c63f37e2ad068ba1 Mon Sep 17 00:00:00 2001
From: "Pascal J. Bourguignon"
Date: Wed, 12 Jan 2011 16:34:26 +0100
Subject: [PATCH] Added up to p73.lisp.

index.html  55 
p70.lisp  89 ++++++++++++++++++++++
p70b.lisp  145 +++++++++++++++++++++++++++++++++++
p70c.lisp  142 +++++++++++++++++++++++++++++++++++
p71.lisp  30 ++++++++
p72.lisp  39 ++++++++++
p73.lisp  249 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 694 insertions(+), 55 deletions()
create mode 100644 p70.lisp
create mode 100644 p70b.lisp
create mode 100644 p70c.lisp
create mode 100644 p71.lisp
create mode 100644 p72.lisp
create mode 100644 p73.lisp
diff git a/index.html b/index.html
index 5c4aeb7..01d415a 100644
 a/index.html
+++ b/index.html
@@ 194,62 +194,7 @@ P60 (**) Construct heightbalanced binary trees with a given number of nodes
Find out how many heightbalanced trees exist for N = 15.
Multiway Trees
A multiway tree is composed of a root element and a (possibly empty) set of successors which are multiway trees themselves. A multiway tree is never empty. The set of successor trees is sometimes called a forest.

[p70]

In Prolog we represent a multiway tree by a term t(X,F), where X denotes the root node and F denotes the forest of successor trees (a Prolog list). The example tree depicted opposite is therefore represented by the following Prolog
term:

T = t(a,[t(f,[t(g,[])]),t(c,[]),t(b,[t(d,[]),t(e,[])])])

P70B (*) Check whether a given term represents a multiway tree
 Write a predicate istree/1 which succeeds if and only if its argument is a Prolog term representing a multiway tree.
 Example:
 * istree(t(a,[t(f,[t(g,[])]),t(c,[]),t(b,[t(d,[]),t(e,[])])])).
 Yes

P70C (*) Count the nodes of a multiway tree
 Write a predicate nnodes/1 which counts the nodes of a given multiway tree.
 Example:
 * nnodes(t(a,[t(f,[])]),N).
 N = 2

 Write another version of the predicate that allows for a flow pattern (o,i).

P70 (**) Tree construction from a node string
 [p70]
 We suppose that the nodes of a multiway tree contain single characters. In the depthfirst order sequence of its nodes, a special character ^ has been inserted whenever, during the tree traversal, the move is a backtrack to the
 previous level.

 By this rule, the tree in the figure opposite is represented as: afg^^c^bd^e^^^

 Define the syntax of the string and write a predicate tree(String,Tree) to construct the Tree when the String is given. Work with atoms (instead of strings). Make your predicate work in both directions.

P71 (*) Determine the internal path length of a tree
 We define the internal path length of a multiway tree as the total sum of the path lengths from the root to all nodes of the tree. By this definition, the tree in the figure of problem P70 has an internal path length of 9. Write a
 predicate ipl(Tree,IPL) for the flow pattern (+,).

P72 (*) Construct the bottomup order sequence of the tree nodes
 Write a predicate bottomup(Tree,Seq) which constructs the bottomup sequence of the nodes of the multiway tree Tree. Seq should be a Prolog list. What happens if you run your predicate backwords?

P73 (**) Lisplike tree representation
 There is a particular notation for multiway trees in Lisp. Lisp is a prominent functional programming language, which is used primarily for artificial intelligence problems. As such it is one of the main competitors of Prolog. In
 Lisp almost everything is a list, just as in Prolog everything is a term.

 The following pictures show how multiway tree structures are represented in Lisp.
 [p73]
 Note that in the "lispy" notation a node with successors (children) in the tree is always the first element in a list, followed by its children. The "lispy" representation of a multiway tree is a sequence of atoms and parentheses '
 (' and ')', which we shall collectively call "tokens". We can represent this sequence of tokens as a Prolog list; e.g. the lispy expression (a (b c)) could be represented as the Prolog list ['(', a, '(', b, c, ')', ')']. Write a
 predicate treeltl(T,LTL) which constructs the "lispy token list" LTL if the tree is given as term T in the usual Prolog notation.

 Example:
 * treeltl(t(a,[t(b,[]),t(c,[])]),LTL).
 LTL = ['(', a, '(', b, c, ')', ')']

 As a second, even more interesting exercise try to rewrite treeltl/2 in a way that the inverse conversion is also possible: Given the list LTL, construct the Prolog tree T. Use difference lists.
Graphs
diff git a/p70.lisp b/p70.lisp
new file mode 100644
index 0000000..546cd3e
 /dev/null
+++ b/p70.lisp
@@ 0,0 +1,89 @@
+#(and) "
+
+P70 (**) Tree construction from a node string
+
+ We suppose that the nodes of a multiway tree contain single
+ characters. In the depthfirst order sequence of its nodes, a
+ special character ^ has been inserted whenever, during the tree
+ traversal, the move is a backtrack to the previous level.
+
+ By this rule, the tree in the figure opposite is represented as:
+ afg^^c^bd^e^^^
+
+ a
+ /\
+ /  \
+ f c b
+  / \
+ g d e
+
+ Define the syntax of the string and write a predicate
+ tree(String,Tree) to construct the Tree when the String is
+ given. Work with atoms (instead of strings). Make your predicate
+ work in both directions.
+"
+
+(load "p70c")
+(load "rdp")
+
+;; Solution: in lisp, we write two function, to parse and to generate.
+;; Again parsing and generating are trivial, using a parser generator:
+
+(defgrammar multiwaytreestring
+ :terminals ((label "[^^]")) ; one char, not ^
+ :start tree
+ :rules ((> tree
+ (opt node)
+ :action (if (null $1)
+ (makeemptymultiwaytree)
+ $1)) ; it's identity, but makeemptymultiwaytree
+ ; could be defined otherwise.
+ (> node
+ label (rep node) "^"
+ :action (makemultiwaytree :label (readfromstring (second $1))
+ :children $2))))
+
+;; (PARSEMULTIWAYTREESTRING "afg^^c^bd^e^^^")
+;; > #S(MULTIWAYTREE
+;; :LABEL A
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL F
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL G
+;; :CHILDREN NIL)))
+;; #S(MULTIWAYTREE
+;; :LABEL C
+;; :CHILDREN NIL)
+;; #S(MULTIWAYTREE
+;; :LABEL B
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL D
+;; :CHILDREN NIL)
+;; #S(MULTIWAYTREE
+;; :LABEL E
+;; :CHILDREN NIL)))))
+;;
+;; (PARSEMULTIWAYTREESTRING "")
+;; > NIL
+
+
+(defun multiwaytreefromstring (string)
+ (PARSEMULTIWAYTREESTRING string))
+
+
+;; and walking the tree:
+
+(defun multiwaytreetostring (tree)
+ (cond ((emptymultiwaytreep tree) "")
+ ((nonemptymultiwaytreep tree)
+ (format nil "~A~{~A~}^"
+ (multiwaytreelabel tree)
+ (mapcar (function multiwaytreetostring)
+ (multiwaytreechildren tree))))
+ (t (error "Not a multiwaytree ~S" tree))))
+
+
+;; (multiwaytreetostring #S(MULTIWAYTREE :LABEL A :CHILDREN (#S(MULTIWAYTREE :LABEL F :CHILDREN (#S(MULTIWAYTREE :LABEL G :CHILDREN NIL))) #S(MULTIWAYTREE :LABEL C :CHILDREN NIL) #S(MULTIWAYTREE :LABEL B :CHILDREN (#S(MULTIWAYTREE :LABEL D :CHILDREN NIL) #S(MULTIWAYTREE :LABEL E :CHILDREN NIL))))))
+;; > "AFG^^C^BD^E^^^"
+
+;;;; THE END ;;;;
diff git a/p70b.lisp b/p70b.lisp
new file mode 100644
index 0000000..169b998
 /dev/null
+++ b/p70b.lisp
@@ 0,0 +1,145 @@
+#(and) "
+
+Multiway Trees
+
+A multiway tree is composed of a root element and a (possibly empty)
+set of successors which are multiway trees themselves. A multiway tree
+is never empty. The set of successor trees is sometimes called a
+forest.
+
+[p70]
+
+In Prolog we represent a multiway tree by a term t(X,F), where X
+denotes the root node and F denotes the forest of successor trees (a
+Prolog list). The example tree depicted opposite is therefore
+represented by the following Prolog term:
+
+T = t(a,[t(f,[t(g,[])]),t(c,[]),t(b,[t(d,[]),t(e,[])])])
+
+
+"
+
+;; In lisp we could represent a multiway tree in multiple ways.
+;; Let's just abstract it away using defstruct.
+
+
+(defstruct (multiwaytree
+ (:predicate nonemptymultiwaytreep))
+
+ label
+ children)
+
+;; Again, if lists are wanted instead of structures, (:type list) can
+;; be used; if vectors, then (:type vector). In both cases, if the
+;; list or vector must start with the symbol MULTIWAYTREE, the :named
+;; option can be added.
+
+
+(defun makeemptymultiwaytree ()
+ 'nil)
+(defun emptymultiwaytreep (tree)
+ (null tree))
+
+(defun multiwaytreep (tree)
+ (or (emptymultiwaytreep tree)
+ (nonemptymultiwaytreep tree)))
+
+
+
+#(and) "
+
+P70B (*) Check whether a given term represents a multiway tree
+
+ Write a predicate istree/1 which succeeds if and only if its
+ argument is a Prolog term representing a multiway tree.
+
+ Example:
+ * istree(t(a,[t(f,[t(g,[])]),t(c,[]),t(b,[t(d,[]),t(e,[])])])).
+ Yes
+"
+
+;; Badass solution:
+
+(defun istree (tree)
+ (multiwaytreep tree))
+
+
+;; In practice, nothing more than the badass solution is needed. For
+;; the exercise, we may check that the children are multiway trees
+;; too.
+
+(defun istree (tree)
+ (cond
+ ((emptymultiwaytreep tree) t)
+ ((nonemptymultiwaytreep tree)
+ (every (function istree) (multiwaytreechildren tree)))))
+
+
+;; Actually, in presence of circular structures, the above istree may
+;; not terminate. Since those exercices are boring, we'll implement
+;; an istree that checks for circular structures too:
+
+
+(defun istree (tree)
+ (let ((nodes (makehashtable)))
+ (labels ((multiwaynodep (node)
+ (cond
+ ((emptymultiwaytreep node) t)
+ ((not (nonemptymultiwaytreep node))
+ (returnfrom istree (values nil :nontree node))) ; short circuit exit
+ ((gethash node nodes)
+ (returnfrom istree (values nil :circular node))) ; short circuit exit
+ (t
+ (setf (gethash node nodes) t)
+ (every (function multiwaynodep) (multiwaytreechildren node))))))
+ (multiwaynodep tree))))
+
+
+(let* ((child (makemultiwaytree :label 'child))
+ (root (makemultiwaytree :label 'root :children (list child))))
+ (setf (multiwaytreechildren child) (list root))
+ (assert (equal (list nil :circular root) (multiplevaluelist (istree root)))))
+
+(let* ((child (makemultiwaytree :label 'child :children '(a b c)))
+ (root (makemultiwaytree :label 'root :children (list child))))
+ (assert (equal '(nil :nontree a) (multiplevaluelist (istree root)))))
+
+(let* ((child (makemultiwaytree
+ :label 'child
+ :children (list (makemultiwaytree :label 'a)
+ (makemultiwaytree :label 'b)
+ (makemultiwaytree :label 'c))))
+ (root (makemultiwaytree :label 'root :children (list child))))
+ (assert (istree root)))
+
+
+;; Notice that CL provides for each structure a printer function
+;; producing a readable form of the structure:
+;;
+;; (let* ((child (makemultiwaytree
+;; :label 'child
+;; :children (list (makemultiwaytree :label 'a)
+;; (makemultiwaytree :label 'b)
+;; (makemultiwaytree :label 'c))))
+;; (root (makemultiwaytree :label 'root :children (list child))))
+;; root)
+;; > #S(MULTIWAYTREE
+;; :LABEL ROOT
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL CHILD
+;; :CHILDREN (#S(MULTIWAYTREE :LABEL A :CHILDREN NIL)
+;; #S(MULTIWAYTREE :LABEL B :CHILDREN NIL)
+;; #S(MULTIWAYTREE :LABEL C :CHILDREN NIL)))))
+;;
+;;
+;;
+;; So we can also write literal multiwaytrees as:
+;;
+;; #S(multiwaytree :label example :children (#S(multiwaytree :label a) #S(multiwaytree :label b)))
+;; > #S(MULTIWAYTREE :LABEL EXAMPLE
+;; :CHILDREN (#S(MULTIWAYTREE :LABEL A :CHILDREN NIL)
+;; #S(MULTIWAYTREE :LABEL B :CHILDREN NIL)))
+
+
+;;;; END ;;;;
+
diff git a/p70c.lisp b/p70c.lisp
new file mode 100644
index 0000000..e679608
 /dev/null
+++ b/p70c.lisp
@@ 0,0 +1,142 @@
+#(and) "
+
+P70C (*) Count the nodes of a multiway tree
+
+ Write a predicate nnodes/1 which counts the nodes of a given multiway tree.
+ Example:
+ * nnodes(t(a,[t(f,[])]),N).
+ N = 2
+
+ Write another version of the predicate that allows for a flow pattern (o,i).
+
+"
+(load "p70b")
+
+
+(defun multiwaytreecountnodes (tree)
+ (cond
+ ((emptymultiwaytreep tree)
+ 0)
+ ((nonemptymultiwaytreep tree)
+ (+ 1 (reduce (function multiwaytreecountnodes)
+ (multiwaytreechildren tree))))
+ (t
+ (error "Not a multiway tree: ~S" tree))))
+
+
+
+
+;; The other version of the prolog predicate generates all the trees
+;; that have the given number of nodes.
+
+
+(defun change (n)
+ (cons (list n)
+ (loop
+ :for i :from 1 :below n
+ :for subchanges = (change i)
+ :nconc (mapcar (lambda (subchange)
+ (cons ( n i) subchange))
+ subchanges))))
+
+(defun crossproduct (sets)
+ "
+SETS is a list of lists.
+Returns a list containing each one element taken from each lists in SETS.
+"
+ (cond
+ ((endp sets) '())
+ ((endp (rest sets)) (mapcar (function list) (first sets)))
+ (t (mapcan (lambda (crosses)
+ (mapcan (lambda (item)
+ (list (cons item crosses)))
+ (first sets)))
+ (crossproduct (rest sets))))))
+
+;; (crossproduct '())
+;; (crossproduct '((a1 a2) (b1 b2)))
+;; (crossproduct '((a1 a2) (b1 b2 b3) (c1 c2)))
+
+
+;; Notice that we consider that the order of the children matters,
+;; but the identity of the children does not.
+;;
+;; So a node with two children, the first of 2 nodes, and the other of
+;; 1 node, will be different from a node with two children, the first
+;; of 1 node and the other of 2 nodes.
+
+(defun generatemultiwaytreeswithnodes (nodecount nextlabel)
+ "Return a list of multiwaytrees with NODECOUNT nodes."
+ (case nodecount
+ ((0) (list (makeemptymultiwaytree)))
+ ((1) (list (makemultiwaytree :label (funcall nextlabel))))
+ (otherwise
+ (loop
+ :with subtrees = (coerce
+ (loop
+ :for remainingcount :below nodecount
+ :collect (generatemultiwaytreeswithnodes remainingcount nextlabel))
+ 'vector)
+ :for change :in (change (1 nodecount))
+ :nconc (mapcar (lambda (children)
+ (makemultiwaytree
+ :label (funcall nextlabel)
+ :children children))
+ (crossproduct (mapcar (lambda (childrencount) (aref subtrees childrencount))
+ change)))))))
+
+
+;; (generatemultiwaytreeswithnodes 4 (let ((n 0)) (lambda () (incf n))))
+;; >
+;; (#S(MULTIWAYTREE
+;; :LABEL 9
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 7
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 6
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 5
+;; :CHILDREN NIL)))))))
+;; #S(MULTIWAYTREE
+;; :LABEL 10
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 8
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 4
+;; :CHILDREN NIL)
+;; #S(MULTIWAYTREE
+;; :LABEL 4
+;; :CHILDREN NIL)))))
+;; #S(MULTIWAYTREE
+;; :LABEL 11
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 3
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 2
+;; :CHILDREN NIL)))
+;; #S(MULTIWAYTREE
+;; :LABEL 1
+;; :CHILDREN NIL)))
+;; #S(MULTIWAYTREE
+;; :LABEL 12
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 1
+;; :CHILDREN NIL)
+;; #S(MULTIWAYTREE
+;; :LABEL 3
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 2
+;; :CHILDREN NIL)))))
+;; #S(MULTIWAYTREE
+;; :LABEL 13
+;; :CHILDREN (#S(MULTIWAYTREE
+;; :LABEL 1
+;; :CHILDREN NIL)
+;; #S(MULTIWAYTREE
+;; :LABEL 1
+;; :CHILDREN NIL)
+;; #S(MULTIWAYTREE
+;; :LABEL 1
+;; :CHILDREN NIL))))
+
+;;;; THE END ;;;;
diff git a/p71.lisp b/p71.lisp
new file mode 100644
index 0000000..6416477
 /dev/null
+++ b/p71.lisp
@@ 0,0 +1,30 @@
+#(and) "
+
+P71 (*) Determine the internal path length of a tree
+
+ We define the internal path length of a multiway tree as the total
+ sum of the path lengths from the root to all nodes of the tree. By
+ this definition, the tree in the figure of problem P70 has an
+ internal path length of 9. Write a predicate ipl(Tree,IPL) for the
+ flow pattern (+,).
+
+"
+
+;; A simple direct recursive solution:
+
+(defun multiwaytreetotalpathlength (tree sofar)
+ "
+SOFAR is the length of path from the root to TREE.
+Returns the total length of path from the root to each nodes of TREE.
+"
+ (reduce (function +)
+ (multiwaytreechildren tree)
+ :key (lambda (node) (multiwaytreetotalpathlength node (1+ sofar)))
+ :initialvalue sofar))
+
+(defun ipl (tree)
+ (multiwaytreetotalpathlength tree 0))
+
+(assert (= 9 (ipl (parsemultiwaytreestring "AFG^^C^BD^E^^^"))))
+
+;;;; THE END ;;;;
diff git a/p72.lisp b/p72.lisp
new file mode 100644
index 0000000..7698d9d
 /dev/null
+++ b/p72.lisp
@@ 0,0 +1,39 @@
+#(and) "
+
+P72 (*) Construct the bottomup order sequence of the tree nodes
+
+ Write a predicate bottomup(Tree,Seq) which constructs the
+ bottomup sequence of the nodes of the multiway tree Tree. Seq
+ should be a Prolog list. What happens if you run your predicate
+ backwords?
+"
+
+;; "Bottomup order sequence of tree nodes" is an idiosyncrasy
+;; (google for it, there's no definition!).
+;; Perhaps it means postfix order.
+;; Right, it's the postfix order. The prolog solution gives:
+;; ? bottom_up(t(a,[t(f,[t(g,[])]),t(c,[]),t(b,[t(d,[]),t(e,[])])]),L).
+;; L = [g, f, c, d, e, b, a].
+
+
+(defun multiwaytreepostfixorder (tree)
+ "
+Returns a list of node labels in the postfix order.
+"
+ (reduce (function nconc)
+ (multiwaytreechildren tree)
+ :key (function multiwaytreepostfixorder)
+ :initialvalue (list (multiwaytreelabel tree))
+ :fromend t))
+;; :fromend is needed so that the initialvalue is placed on the right.
+;; It also proves beneficial since then the lists are walked only once per level.
+
+;; (multiwaytreepostfixorder (parsemultiwaytreestring "AFG^^C^BD^E^^^"))
+;; > (G F C D E B A)
+
+
+(defun bottomup (tree)
+ (multiwaytreepostfixorder tree))
+
+
+;;;; THE END ;;;;
diff git a/p73.lisp b/p73.lisp
new file mode 100644
index 0000000..e76c9ea
 /dev/null
+++ b/p73.lisp
@@ 0,0 +1,249 @@
+#(and) "
+
+P73 (**) Lisplike tree representation
+
+ There is a particular notation for multiway trees in Lisp. Lisp is
+ a prominent functional programming language, which is used
+ primarily for artificial intelligence problems. As such it is one
+ of the main competitors of Prolog. In Lisp almost everything is a
+ list, just as in Prolog everything is a term.
+
+ The following pictures show how multiway tree structures are
+ represented in Lisp.
+
+ Note that in the \"lispy\" notation a node with successors (children)
+ in the tree is always the first element in a list, followed by its
+ children. The \"lispy\" representation of a multiway tree is a
+ sequence of atoms and parentheses ' (' and ')', which we shall
+ collectively call \"tokens\". We can represent this sequence of
+ tokens as a Prolog list; e.g. the lispy expression (a (b c)) could
+ be represented as the Prolog list ['(', a, '(', b, c, ')',
+ ')']. Write a predicate treeltl(T,LTL) which constructs the
+ \"lispy token list\" LTL if the tree is given as term T in the usual
+ Prolog notation.
+
+ Example:
+ * treeltl(t(a,[t(b,[]),t(c,[])]),LTL).
+ LTL = ['(', a, '(', b, c, ')', ')']
+
+ As a second, even more interesting exercise try to rewrite
+ treeltl/2 in a way that the inverse conversion is also possible:
+ Given the list LTL, construct the Prolog tree T. Use difference
+ lists.
+
+"
+(load "rdp")
+(usepackage :com.informatimago.rdp)
+(load "p70")
+
+"
+Again there are several problem with the problem statement.
+
+In lisp, there are no parentheses. Only cons cells and atoms. The
+lisp expression (a (b c)) doesn't represent a sequence of symbols and
+parentheses, but a structure made of cons cells and symbols:
+
+ ++
+  (a (b c)) 
+  
+  +++ +++ 
+   *  * > * NIL 
+  +++ +++ 
+    
+  v v 
+  ++ +++ +++ 
+   A   *  * > * NIL 
+  ++ +++ +++ 
+    
+  v v 
+  ++ ++ 
+   B   C  
+  ++ ++ 
+ ++
+
+
+The correct representation of such a structure in prolog would be:
+
+ [a,[b,c]]
+
+and not the proposed:
+
+ ['(', a, '(', b, c, ')', ')']
+
+A textual representation of that structure would be a STRING, not a
+list of characters:
+
+ \"(a (b c))\"
+
+we can build a list of characters as an intermediate representation of
+the string, but it is not too useful. It would not be done usually in
+lisp programs.
+
+On the other hand, when writing a parser, it would be possible to
+separate the lexer from the parser, having the lexer generate a list
+of tokens to be passed to the parser.
+
+
+
+Notice also that if the problem was to produce the multiwaytree as a
+sexp where each node is represented by a list containing the label as
+first element, and a sublist containing the children as second
+element, then we would just have to give the (:type list) option to
+the defstruct to have it represent the trees that way! But the syntax
+defined above specifies the irregularty that leaf nodes are
+represented by the mere label of the leaf, instead of a list with the
+label and an empty list of children.
+
+"
+
+;; Badass solution:
+
+(defstruct (multiwaytree
+ (:type list))
+ label
+ children)
+
+;; (parsemultiwaytreestring "AFG^^C^BD^E^^^")
+;; > (A ((F ((G NIL))) (C NIL) (B ((D NIL) (E NIL)))))
+
+
+
+;; Let's generate the lisp sexp with the leaves reprensted by their
+;; labels. This doesn't need that the multiway trees be represented a
+;; lists, since we keep using the functional abstraction.
+
+(defun processleaves (tree)
+ (cond
+ ((emptymultiwaytreep tree) tree)
+ ((endp (multiwaytreechildren tree)) (multiwaytreelabel tree))
+ (t (cons (multiwaytreelabel tree)
+ (mapcar (function processleaves)
+ (multiwaytreechildren tree))))))
+
+(assert (equal (processleaves (parsemultiwaytreestring "AFG^^C^BD^E^^^"))
+ '(A (F G) C (B D E))))
+
+;; Badass solution, using lisp sexps to generate first the string,
+;; then the wanted list:
+
+
+(defun myprin1tostring (object)
+ (let ((*printcircle* nil)
+ (*printcase* :upcase)
+ (*printreadably* nil)
+ (*printpretty* nil)
+ (*printbase* 10.)
+ (*printradix* nil)
+ (*printlevel* nil)
+ (*printlength* nil)
+ (*printlines* nil))
+ (prin1tostring object)))
+
+(defun treeltl (tree)
+ ;; How unfunny is that!
+ (coerce (remove #\space (myprin1tostring (processleaves tree))) 'list))
+
+
+(assert (equal (treeltl (parsemultiwaytreestring "AFG^^C^BD^E^^^"))
+ '(#\( #\A #\( #\F #\G #\) #\C #\( #\B #\D #\E #\) #\))))
+
+
+;; We could also make the nonparenthesis characters back into symbols:
+
+(defun treeltl (tree)
+ (map 'list
+ (lambda (ch)
+ (if (alphanumericp ch)
+ (intern (string ch))
+ ch))
+ (remove #\space (myprin1tostring (processleaves tree)))))
+
+(assert (equal (treeltl (parsemultiwaytreestring "AFG^^C^BD^E^^^"))
+ '(#\( A #\( F G #\) C #\( B D E #\) #\))))
+
+
+;; Finally we could also repeat again and again the same tree walking
+;; and generation of the list:
+
+
+(defun treeltl (tree)
+ (cond
+ ((emptymultiwaytreep tree) "") ; should occur only when root is empty.
+ ((endp (multiwaytreechildren tree))
+ (list (multiwaytreelabel tree)))
+ (t (nconc
+ (list #\( (multiwaytreelabel tree))
+ (mapcan (function treeltl)
+ (multiwaytreechildren tree))
+ (list #\))))))
+
+
+(assert (equal (treeltl (parsemultiwaytreestring "AFG^^C^BD^E^^^"))
+ '(#\( A #\( F G #\) C #\( B D E #\) #\))))
+
+
+;; Now, for the inverse function, parsing the list could be done
+;; directly; we'd have to provide a pseudolexer to replace the lexer
+;; that scans source strings. For a simple solution we will just
+;; convert the list into a string and let the generated scanner do its
+;; work:
+
+
+(defgrammar multiwaytreeparenthesizedstring
+ :terminals ((label "[^^]")) ; one char, not ^
+ :start tree
+ :rules ((> tree
+ (opt (alt parnode leaf))
+ :action (if (null $1)
+ (makeemptymultiwaytree)
+ $1))
+ ; it's identity, but makeemptymultiwaytree
+ ; could be defined otherwise.
+ (> parnode
+ "(" label (rep tree) ")"
+ :action (makemultiwaytree :label (readfromstring (second $2))
+ :children $3))
+ (> leaf
+ label
+ :action (makemultiwaytree :label (readfromstring (second $1))))))
+
+(defun ltltree (ltl)
+ (parsemultiwaytreeparenthesizedstring
+ (format nil "~{~A~}" ltl)))
+
+(assert (equal (ltltree '(#\( A #\( F G #\) C #\( B D E #\) #\)))
+ (parsemultiwaytreestring "AFG^^C^BD^E^^^")))
+
+
+
+
+;; Another solution would be to use the lisp reader, since the list
+;; should contain well balanced parentheses, and then convert the
+;; obtained sexp into a tree. Notice how much simplier this is, to
+;; process simple grammar sufficiently similar to sexps: there's no
+;; need to involve the complexities of a parser generator.
+
+(defun multiwaytreefromsexp (node)
+ (cond
+ ((null node) (makeemptymultiwaytree))
+ ((atom node) (makemultiwaytree :label node)) ; a leaf
+ (t (destructuringbind (label &rest children) node
+ (makemultiwaytree :label label
+ :children (mapcar (function multiwaytreefromsexp)
+ children))))))
+
+(defun ltltree (ltl)
+ (multiwaytreefromsexp (let ((*readeval* nil)
+ (*readbase* 10.)
+ (*readtable* (copyreadtable nil)))
+ (readfromstring (format nil "~{ ~A ~}" ltl)))
+ ;; we get a list such as (A (F G) C (B D E))
+ ))
+
+(assert (equal (ltltree '(#\( A #\( F G #\) C #\( B D E #\) #\)))
+ (parsemultiwaytreestring "AFG^^C^BD^E^^^")))
+
+
+;;;; THE END ;;;;
+
+

2.1.4