J is great! It is a wonderful little language for data analysis tasks. However, to programmers used to working in modern dynamic languages, it sometimes feels a little restrictive. In particular, a ubiquitous feature in the post-Python (let’s call it) era is hash-maps. Even in older languages, like Common Lisp, the association list – allowing abritrary mappings between keys and values, is a very common idiom.

J exposes no native functionality that exactly meets this use case, one common application of which is named, optional arguments to functions.

In developing an interactive gnuplot interface for J, I wanted to pass optional keyword arguments to functions so that plots can be easily customized. So I developed a simple representation of key/val pairs which is efficient enough for small collections of named values.

Consider:

nil =: (0$0) rankOne =: 1: -: (#@:$) rankTwo =: 2: -: (#@:$) talliesEven =: 0: -: (2: | #) twoColumns =: 2: -: 1&{@:$ opts =: monad define keysandvals =. y assert. rankOne keysandvals assert. talliesEven keysandvals ii =. 2 | (i. #y) keys =. (-. ii) # y vals =. ii # y keys (>@:[ ; ])"(0 0) vals )

Opts is a monadic verb which takes a flat boxed array of even length and returns a rank two boxed array whose first column is keys and whose second column is values:

opts 'key1';10;'key2';11 +----+--+ |key1|10| +----+--+ |key2|11| +----+--+

Look up is simple: find the key’s index in the first column and index the second column with it. Return nil if the key isn’t found.

getopt =: dyad define options =. x key =. y assert. rankTwo options assert. twoColumns options if. 0 -: #options do. nil else. ii =. ((i.&1)@:(((key&-:@:>)"0)@:(((0&{)@:|:)))) options if. ii < #options do. (>@:(ii&{)@:(1&{)@:|:) options else. nil end. end. )

Eg:

(opts 'key1';10;'key2';11) getopt 'key1' -> 10

We can now define a handy conjunction to allow the specification of a default value:

dft =: conjunction define : r =. x u y if. r -: nil do. n else. r end. )

Which we use this way:

(opts 'key1';10;'key2';11) getopt dft '___' 'key1' -> 10 (opts 'key1';10;'key2';11) getopt dft '___' 'key3' '---'

This allows us to pass optional arguments to verbs and specify default values relatively easily, as in this example from my gnuplot library:

histogram =: verb define (ensureGnuPlot'') histogram y : data =. y if. boxedP x do. options =. x gph =. options getopt dft (ensureGnuPlot'') 'gnuplot' else. gph =. x options =. (opt '') end. mn =. <./ data mx =. >./ data bw =. options getopt dft (0.1&* mx-mn) 'binwidth' pttl =. options getopt dft '' 'plot-title' 'binwidth=%f

' gph gpfmt <bw gph send 'set boxwidth binwidth' gph send 'bin(x,width)=width*floor(x/width) + binwidth/2.0' s =. 'plot "%s" using (bin($1,binwidth)):(1.0) smooth freq title "%s" with boxes' s gph gpfmt ((asFile (asVector data));pttl) )

Where, in the dyadic case, we detect whether x is boxed, and if so, treat it as a list of options. We extract each option by name, providing a reasonable default.

This seems like a common problem, so I am wondering if anyone else in the J community has solved it before in a different way?