diff --git a/arr.sml b/arr.sml
index 23e66d652828e0177ad99195405e28d8352ed0a6..eee23ab517990a653a8328e8126b211888a15cb3 100644
--- a/arr.sml
+++ b/arr.sml
@@ -16,14 +16,14 @@ exception Index;
 exception BadStop;
 exception NYI;
 (* atom constructors *)
-fun Word(x) = Lf(N(x));
-fun Fun0(f) = Lf(FN(f));
-fun Fun1(f) = Lf(FM(f));
-fun Fun2(f) = Lf(FD(f));
+fun Word x = Lf(N(x));
+fun Fun0 f = Lf(FN(f));
+fun Fun1 f = Lf(FM(f));
+fun Fun2 f = Lf(FD(f));
 (* array constructor *)
-fun Array([])    = Zl
-  | Array([x])   = x
-  | Array(x::xs) = Nd(x,Array(xs)); (* TODO: automatically box? *)
+fun Array []     = Zl
+  | Array [x]    = x
+  | Array (x::xs) = Nd(x,Array(xs)); (* TODO: automatically box? *)
 (* return tree-element type *)
 fun tt Zl        = "Zl"
   | tt (Lf(x))   = "Lf"
@@ -36,33 +36,36 @@   | leaves (Lf(x))   = [Lf(x)]
   | leaves (Nd(x,y)) = x::(leaves y)
   | leaves (Bx(s,a)) = leaves a;
 (* unbox a boxed array *)
-fun unbox(Bx(s,a)) = a
-  | unbox(x)       = x;
+fun unbox (Bx(s,a)) = a
+  | unbox (x)       = x;
 (* return length of array *)
-fun tally(Zl)         = 0w0
-  | tally(Lf(a:atom)) = 0w1
-  | tally(Nd(x,y))    = 0w1 + tally y
-  | tally(Bx(s,a))    = tally (unbox a);
+fun tally Zl          = 0w0
+  | tally (Lf(a:atom)) = 0w1
+  | tally (Nd(x,y))    = 0w1 + tally y
+  | tally (Bx(s,a))    = tally (unbox a);
 (* box an array *)
-fun Box(a:arr) = Bx(Array([Word(tally a)]),a);
+fun Box (a:arr) = Bx(Array([Word(tally a)]),a);
 (* return shape of boxed array *)
 (* TODO: do we only want this for boxed arrays?  do we want just tally for unboxed arrays? *)
 (* TODO: Do we want a boxed array to be length 1 or the length of the contents? *)
-fun shape(Bx(s,a)) = Box(s)
-  | shape(Nd(x,y)) = Box(Array([Word(tally(Nd(x,y)))]));
-(* return a string representation of an array *)
-fun str(Zl)        = "(Zilde)" (* TODO: box-drawing characters might be nice in the future *)
-  | str(Lf(N(x)))  = Word8.fmt StringCvt.HEX x
-  | str(Lf(FN(x))) = "(Nilad)" (* TODO: would be nice to get actual function names *)
-  | str(Lf(FM(x))) = "(Monad)"
-  | str(Lf(FD(x))) = "(Dyad)"
-  | str(Nd(x,y))   = str(x) ^ " " ^ str(y)
-  | str(Bx(s,a))   = "[" ^ str(a) ^ "]";
+fun shape (Bx(s,a)) = s
+  | shape (Nd(x,y)) = Array([Word(tally(Nd(x,y)))]);
+(* print a string representation of an array *)
+fun str a = 
+  let fun st Zl    = "(Zilde)" (* TODO: box-drawing characters might be nice in the future *)
+        | st (Lf(N(x)))  = StringCvt.padLeft #"0" 2 (Word8.fmt StringCvt.HEX x)
+        | st (Lf(FN(x))) = "(Nilad)" (* TODO: would be nice to get actual function names *)
+        | st (Lf(FM(x))) = "(Monad)"
+        | st (Lf(FD(x))) = "(Dyad)"
+        | st (Nd(x,y))   = (st x) ^ " " ^ (st y)
+        | st (Bx(s,a))   = "[" ^ (st a) ^ "]"
+  in (st a) ^ "\n"
+  end;
 (* return a string representation of the internal structure of an array *)
 fun tree a =
   let fun r s n = concat (List.tabulate (n, fn _ => s));
   in let fun t (Zl)        n = (r " " n) ^ "ZILDE"
-           | t (Lf(N(x)))  n = (r " " n) ^ "LEAF: " ^ (Word8.fmt StringCvt.HEX x)
+           | t (Lf(N(x)))  n = (r " " n) ^ "LEAF: " ^ StringCvt.padLeft #"0" 2 ((Word8.fmt StringCvt.HEX x))
            | t (Lf(FN(x))) n = (r " " n) ^ "LEAF: Nilad" (* TODO: would be nice to get actual function names *)
            | t (Lf(FM(x))) n = (r " " n) ^ "LEAF: Monad"
            | t (Lf(FD(x))) n = (r " " n) ^ "LEAF: Dyad"
@@ -73,19 +76,20 @@    end
   end;
 (* call a nilad *)
 (* TODO: higher-order functions *)
-fun apply0(f) = raise NYI; (* TODO - what if it generates a whole array? *)
+fun apply0 f = f(); (* TODO - what if it generates a whole array? *)
 (* apply a monad to an array *)
 (* TODO: higher-order functions *)
 (* TODO: apply to an atom? *)
-fun apply1(f,Zl)       = raise Domain  (* traverse the array tree, applying f to each leaf in turn *)
-  | apply1(f,Lf(N(x))) = Lf(N(f(x)))
-  | apply1(f,Nd(x,y))  = Nd(apply1(f,x),apply1(f,y));
+fun apply1 f Zl         = raise Domain (* TODO: is this right? *)
+  | apply1 f (Lf(N(x))) = Lf(N(f x))
+  | apply1 f (Nd(x,y))  = Nd((apply1 f x),(apply1 f y))
+  | apply1 f (Bx(s,a))  = raise NYI; (* FIXME *)
 (* apply a dyad to two arrays *)
 (* TODO: higher-order functions *)
 (* TODO: apply to atoms, or a mix of both?  do we need tagged functions for e.g. # that changes dependent on atom or array? *)
-fun apply2(f,x,y) = raise NYI; (* TODO *)
+fun apply2 f x y = raise NYI; (* TODO *)
 (* append an element to an array *)
-fun append(x,a) = Nd(x,a);
+fun append x a = Nd(x,a);
 (* return an element at an index *)
 fun index _ Zl          = Zl (* TODO: Is this the behaviour that we want?  Or should it raise an exception? *)
   | index 0w0 (Lf(x))   = Lf(x)
