J: Tacit Programming
A couple of months ago I wrote about tacit programming with respect to F#, a term which I first came across while reading about the J programming language.
There’s a good introduction to tacit programming on the J website which shows the evolution of a function which originally has several local variables into a state where it has none at all.
I’ve been having a go at writing Roy Osherove’s TDD Kata in J and while I haven’t got very far yet I saw a good opportunity to move the code I’ve written so far into a more tacit style.
From my understanding two of the ways that we can drive towards a tacit style are by removing explicitly passed arguments and variables from our code.
Remove explicitly passed arguments
The second part of the kata requires us to allow new lines separating numbers as well as commas so with the help of the guys on the J mailing list I wrote a function which converts all new lines characters into commas:
replaceNewLines =: 3 : 0 y rplc ('\n';',') )
‘rplc’ takes an input as its left hand argument and a 2 column boxed matrix as its right hand argument.
In this case the left hand argument is ‘y’ which gets passed to ‘replaceNewLines’ and the boxed matrix contains ‘\n’ and ‘,’. The left item in the matrix gets replace by the right item.
We want to get to the point where we don’t have to explicitly pass y - it should just be inferred from the function definition.
As is the case in F# it seems like if we want to do this then we need to have the inferred value (i.e. y) passing as the last argument to a function which in this case means that it needs to be passed as the right hand argument.
‘rplc’ is actually the same as another function ‘stringreplace’ which takes in the arguments the other way around which is exactly what we need.
replaceNewLines =: 3 : 0 ('\n';',') stringreplace y )
The next step is to apply the left hand argument of ‘stringreplace’ but infer the right hand argument.
We can use the bond conjunction (&) to do this. The bond conjunction creates a new function (or verb in J speak) which has partially applied the left argument to the verb passed as the right hand argument.
replaceNewLines =: ('\n' ; ',') & stringreplace
‘replaceNewLines’ represents the partial application of ‘stringReplace’. We can now pass a string to ‘replaceNewLines’ and it will replace the new lines characters with commas.
Remove local variables
My ‘add’ function currently looks like this:
add =: 3 : 0 newY =. replaceNewLines y +/ ". newY )
We want to try and drive ‘add’ to the point where it’s just a composition of different functions.
At the moment on line 3 we have ‘+/’ which can be used to get the sum of a list of numbers.
+/ 1 2 3 > 6
We also have ‘“.’ which converts a character array into numbers.
". '1,2,3' > 1 2 3
In order to compose our 3 functions together without explicitly passing in ‘y’ or ‘newY’ we need to make use of atop conjunction (@) which “combines two verbs into a derived verb that applies the right verb to its argument and then applies the left verb to that result.”
It works in the same way as Haskell’s function composition operator i.e. it applies the functions starting with the one furthest right.
We end up with this:
add =: +/ @ ". @ replaceNewLines
or if we want to inline the whole thing:
add =: +/ @ ". @ ( ('\n' ; ',') & stringreplace )