building trees in j

Table of Contents

1 basic tree building operations

emit
splice some items into the current node
node
start a new node
done
finish a node (returning to the previous one)
drop
remove the last item
goto
go back to a node created earlier

2 a simple tree-builder implementation

The tree is a rank 1 array of parent indices (where _1 indicates root/null)

Here is a straightforward imperative definition of our primitives:

tree =: $0   NB. stores the links to parents.
data =: $0   NB. stores the actual data items.
path =: $0   NB. the stack of parent nodes.
here =: _1   NB. the current parent node.

emit =: monad define "0
  tree =: tree, here
  data =: data, y
  tree
)

node =: monad define "_
  emit y
  path =: path, here
  here =: <: # tree
  tree
)

done =: monad define "_
  here =: {: path
  path =: }: path
  emit y
  tree
)

drop =: monad define "_
  data =: }: data
  tree =: }: tree
)

goto =: monad define "_
  path =: path, here
  here =: y
  tree
)

These verbs all return the tree as a convention, both to to make tracing simpler and to allow easy use in gerunds. (See s-expression parser, below).

3 queries

upfrom =: 3 : 'if. y=_1 do. _1 else. y{tree end.'"0
dnfrom =: 3 : 'if. 0=#y do. $0 else. I. +./"2 tree ="1 0 ;y end.'"1
above =: (_1 -.~ }.)&(upfrom f.^:a:)"0
below =: 13 : '; }. dnfrom each ^:a: < y'
depth =: #@above
treet =: 3 : '(i.#tree),.tree,.data' NB. tree table :)
index =: 3 : '(i.#tree)'

4 an example tree

reset =: verb define
  tree =: path =: data =: $ >: here =: _1
)
tree0 =: verb define
  emit i. 5
  node''
  emit 44 45 46
  done''
  emit 5 6
  node''
  emit 60 61 62
  done''
  goto 4
  emit 44
  done''
  goto data i. 61
  emit 610 611
  done''
)

5 in action

   reset''

   tree0''

   treet''
 0 _1   0
 1 _1   1
 2 _1   2
 3 _1   3
 4 _1   4
 5  4  44
 6  4  45
 7  4  46
 8 _1   5
 9 _1   6
10  9  60
11  9  61
12  9  62
13  4  44
14 11 610
15 11 611

   upfrom data i. 610
11
   data {~ upfrom data i. 610
61
   data {~ upfrom data i. 610 61
61 6
   data {~ above data i. 610
61 6
   data {~ below 4
44 45 46 44

6 TODO s-expression parser

Parsing lisp-style s-expressions is simply a matter of mapping each character to a corresponding tree builder routine:

rsx =: (node`done`emit)@.('()' & i.)"0  NB. 'read s-expression'

In this version, every character is mapped to its own node, but it should be easy to update this to use j's sequential machine primitive to break the input into tokens first. (TODO)

   NB. the trace is a large ugly matrix that shows the
   NB. tree at each step of the parse.
   trace =. rsx'(banana (creme (pie)))' [ reset''

   tree
_1 0 0 0 0 0 0 0 0 8 8 8 8 8 8 8 15 15 15 8 0 _1

   data
(banana (creme (pie)))

   NB. the characters grouped by parent:
   tree</.data
┌──┬─────────┬────────┬───┐
│()│banana ()│creme ()│pie│
└──┴─────────┴────────┴───┘

   NB. show depth of each character node graphically:
   |:(data ,~"0 1  '_' #~ "0 >:) depth index''
______________________
 ____________________
         ___________
                ___
(banana (creme (pie)))

7 maybe later

type =: $0   NB. a type marker for each node in the tree.
tags =: $.$0 NB. sparse array holding meta data about nodes.

8 treebuild.ijs

This code is maintained as a literate program with org-babel for emacs. You can retrieve it in any of three formats:

<<builder>>
<<queries>>
<<example>>
<<rsx>>

9 references