Earlier today, Tracy showed me a "programming kata":

   http://osherove.com/tdd-kata-1/

it describes a program to implement for the sake of learning TDD.   Right now, 
I have no interest in TDD, but I found another way to
render the task education and amusing.   

In [1], I mentioned some of the ways the J programmers can and do avoid 
explicit, ham-handed flow control, and how flow control
often implicit in and a natural part of a J program.  I didn't define what this 
means precisely, but I gave the following example:

    if ( pathString.lastChar != "\" )
    {
         pathString.append("\");
    }

which is explicit, imperative, startling (in the sense that it interrupts your 
reading of the enclosing program, gives you pause,
and makes you "meta think" ), and irrelevant to the purpose of the enclosing 
function.  I contrasted this with the equivalent J
expression:

    (, '\' #~ '\'~:{:) pathString

which, in broad strokes, reads "append to the input N copies of '\', where N is 
0 or 1 according to whether the last char of the
input is already a '\'", and is an unintrusive, implicit, flowing part of the 
enclosing program, and how the predicate is wedded to
the consequence (as opposed to the pseudocode branch block which in theory 
could be arbitrary).

So, in the grand tradition of constrained writing, I tossed out all the kata 
requirements relating to TDD, and substituted the
constraint that the solution must have only implicit, natural, flow control.  
What does that mean? 

Well, "natural" is a matter of taste, but we certainly must exclude control 
words (if. and friends), and our use of certain
primitives must be judicious.  Certainly  @.  is an obvious "select statement", 
and should be avoided.  But there are even subtler
design decisions; for example, while  (^:predicate)  is more implicit than  
(if. predicate do.)  it is still a strong hint that one
is handling an edge condition, and can interrupt the flow of reading.   I know 
I still haven't defined "natural flow control"*, and
the concept is nebulous, but those who find it appealing may find more traces 
of it in [1].

Nebulous or not, I made an attempt.  Now, the kata is not perfectly defined 
(though it is reflective of "real world" specs), and I
only implemented up to rule 6 ("Numbers bigger than 1000 should be ignored, so 
adding 2 + 1001  = 2"), and ironically I did not test
it very much, but here it is:

           normalize =.  ,~ ('//,',LF) #~ 1-'//'-:2&{. 
           dedelimit =.  ({. ((j.~-.)@e.~ # ]) }.)~ 1 + i.&LF
           stopNeg   =.  [ ('negatives not allowed '&, 13!:8&3~ 1 < #)@:([: ; ' 
' ,&.> ] 8!:0@:#~ 0&>)
           filterBig =.  #~ 1000&>
           add       =:  +/@:filterBig@:stopNeg@:(0 ". dedelimit)@:normalize f.
           
One niggle I have with this solution is in stopNeg, which is a hook of the form 
 [ f  , which functionally reduces to  [  and only
mentions  f  for its side effects.  Ideally, I would've liked to have written  
f  such that it produce its side effect or its input,
similar to  f^:predicate, but as I mentioned, though that form is functional 
and elegant, I wanted my flow control as "implicit" as
possible, and I felt the hidden powering functions of dyad u&m  pursued that 
end better (though I'm not sure  [  f   achieves it).
However, I do feel the particular use of  u&m  here is very natural, because  
13!:8&3  simply means "domain error", and yet happens
to take the error message and the predicate as inputs.

I would be interested in the comments of others, both on the particular "poem" 
and the form of poetry, and I would love to read
other submissions.

-Dan

*  But I know it when I see it (more precisely, its opposite).  The ideal would 
be to turn "flow control" into "natural flow
control", and then give up the control, to produce "natural flow".   It is the 
attempt the "control" the program that is
problematic. 



----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm

Reply via email to