Tuesday, June 7, 2011

smalltalk, apl, soy lisp, and higher order operands

APL, Smalltalk, Lisp. The holy trinity of programming languages. In this post I aim to better explain the Soy Lisp syntax which allows for all three to coexist.

Consider first the ability to drop parens when an expression is terminated via ".":

(func arg1 arg2)
//becomes
func arg1 arg2.

This creates an immediate problem w/ disambiguation when dealing with arguments, well thankfully we do not lose the ability to return to s-expressions when required e.g.:

func arg1 (func2 arg1 arg2).

What else can we glean from smalltalk? Perhaps the ability to cascade via ;, e.g.:

(((func arg1) arg2) arg3)
//becomes
func arg1; arg2; arg3.

In prior posts I have shown my preference for "square lambdas" e.g: [x | x y]. So I will not continue to rant about the benefits here. The last thing I will borrow from smalltalk is keyword constants (whilst keeping lisp keywords) e.g.:

(func :keyword1 var1 :keyword2 (lambda (x) (x :says 'peter))
//becomes
func keyword1: var1 keyword2: [x | x says: 'peter].

The above assumes func is a higher order function which knows how to dispatch keyword selector arguments, which is essentially how I would implement a smalltalk esque language on top of soy.

I think it is clear that functional programming in lisp can benefit from the smalltalk syntax whilst not losing the power of macro expansion and s-expressions.

This brings us to APL the other language I have toyed w/ writing interpreters for. The real crux of apl is working with higher order operators. e.g. reduce which takes on the left hand an operator which it then uses to reduce a set of numbers on the right. In traditional prefix notation this would end up like:

((/ +) 1 2 3 4)
//not bad but noisier than
+ / 1 2 3 4.
//which becomes
(+ / 1 2 3 4)

Which works just fine because + is a higher order operator which knows if its first argument is another operator it should return a function which does a + reduction.

(- (+ 5 5) 5)
//becomes
5 + 5 - 5.

In soy the latter works because numbers are "higher order operands" which can consume operators and return functions which consume more operators/operands as expected. Stay tuned for a web repl for those interested in playing with this. Bare in mind that both forms in all of these examples work with in the same environment as this is all syntactic sugar! Lisp wins again.