Playing Joy

Richard Suchenwirth 2002-04-24 - Joy is a programming language described by Manfred von Thun in http://www.latrobe.edu.au/humanities/research/research-projects/past-projects/joy-programming-language , which has similarities with Forth (see RPN in Tcl), but allows nested lists (and hence things of any complexity) as stack elements. It is radically functional (see Steps towards functional programming) in that it is based on functional composition and has no variables at all - no constants either, for seeming constants are considered functions that take a stack as argument, push their value on the stack, and return the augmented stack. The power of the language is rather in combinators which take one or more functions and return a function. Here the famous K combinator can also be seen in a framework. The Joy mantra could be "Everything is a function".

To read about Joy is a mind-boggling experience. Of course I asked myself: "Can we have that in Tcl too?" How easily RPN can be implemented in Tcl was independently shown by JCW in Trying Forth in Tcl, so my interest focused first on certain combinators.

Primitive recursion is handled by primrec: given two "programs", it pops the stack, and pushes the evaluation of the first "program" if the popped value is zero; otherwise it applies the second "program" to the popped value and a recursive invocation, in which the stack is decremented by 1. My simple implementation limits the first "program" to a constant and the second to a binary expr operator, but that's enough to try the first exercises. To facilitate currying and nesting, the stack should always be the last argument to a "TclJoy" proc, and the modified stack should always be returned. Of course Tcl is Polish in that the command name is always the first word (+ 1 2), while Joy is Reversed Polish (1 2 +) - transpose it in your mind when reading such code.

By isolating the process of recursion into this combinator, typical applications of recursion can be had by simply currying it (see Custom curry) into an interp alias:

 interp alias {} factorial {} primrec 1 *
 interp alias {} sumTo     {} primrec 0 +

which approaches the original Joy style:

 DEFINE factorial == [1] [*] primrec .

Brackets are used in Joy to group lists, similar to braces in Tcl, but a closer approximation is hindered by the fact that the Tcl parser removes braces after heeding them, so {1} is indistinguishable to the called procedure from 1. Will have to think..

 proc primrec {b0 bn Stack} {
    set x [lindex $Stack end]
    if {$x>0} {
        set res [expr $x $bn [primrec $b0 $bn [incr x -1]]]
    } else {
        set res $b0
    }
    lreplace $Stack end end $res
 }
# Here starts my collection of "TclJoy" components:
 proc dup Stack {lappend Stack [lindex $Stack end]}
 proc op2 {op Stack} {
    # binary arithmetic (and comparison) engine
    set x [lindex $Stack end-1]
    set y [lindex $Stack end]
    lreplace $Stack end-1 end [expr $x $op $y]
 }
 foreach op {+ - * / % > >= == <= < !=} {
    interp alias {} $op {} op2 $op
 }

Usage examples (note that the result is always the full stack):

   primrec 1 * {foo bar 5} ==> foo bar 120
   + [dup {2 3 4}]         ==> 2 3 8

Altogether, staying with Polish notation appears just too clumsy - for nested functions, you have to read from the inside out (right to left):

 proc first   Stack {puts Hi; set Stack}
 proc then    Stack {puts and; set Stack}
 proc finally Stack {puts bye!; set Stack}
 ...
 finally [then [first {}]

what in Joy, and RPN again which has a number of operators borrowed from Joy, would look

 first then finally

which admittedly reads much better.


See Pocket Joy 2005 for RS's latest take at Joy.