Jonah
Jonah

Reputation: 16242

Applying an adverb to a list of gerunds

Consider a list of gerunds and some data we wish to apply them to, cyclically:

ms=.*`+`-     NB. list of gerunds
d =.3 4 5 6   NB. some data

We can do:

ms/ d    NB. returns 9, ie, the result of 3 * 4 + 5 - 6

Now we pose the question: how does the result change if we change the order in which we apply the verbs? That is, we consider all 6 possible orders:

allms=. (A.~i.@!@#) ms

which looks like:

┌─┬─┬─┐
│*│+│-│
├─┼─┼─┤
│*│-│+│
├─┼─┼─┤
│+│*│-│
├─┼─┼─┤
│+│-│*│
├─┼─┼─┤
│-│*│+│
├─┼─┼─┤
│-│+│*│
└─┴─┴─┘

To answer the question, we can do:

allms (4 : 'x/ y')"1 d

NB. returns 9 _21 _1 _23 _41 _31

But notice I was forced to use an anonymous, non-tacit verb to accomplish this. Because in order to apply the adverb /, I had to have a named verb. When what I really wanted to do is treat / like a rank 1 verb and "map" it over my list allms, something in spirit like the illegal formulation:

/&d"1 allms  NB. This is invalid J

That is, for each gerund on the list, transform it with the adverb / and apply it to the data d.

J seems to resist this higher-order "treating verbs like data" thinking. So I want to know what the natural J way of approaching this problem would be.

To be specific, you are given the list of gerunds ms and data d, as defined above. The task is to create a verb that returns a list of the results ms/ d, for every possible ordering of ms (ie, a verb that returns 9 _21 _1 _23 _41 _31 in our example). The verb must be a tacit verb.

Upvotes: 4

Views: 221

Answers (2)

Dan Bron
Dan Bron

Reputation: 2324

You don't really want that

There are fundamental syntactic reasons why you can't tacitly slice and dice arguments to operators (adverbs and conjunctions).

Without going into detail, allowing operators to be modified by other operators, like your proposed / modified with "1, would require a fundamental restructuring of J's grammar. And there would be major tradeoffs, in particular to simplicity and expressiveness (i.e. notational elegance)¹,².

So, if you want to distribute operators over gerunds like this, you'll have to write utilities for it, and the most straightforward way by far is by using explicit code. One pre-packaged utility to consider in this domain is the doog script, available in the J Wiki and SVN repo.

Here it is anyway

However, the doog script, like your approach, is fundamentally explicit³. So if you really want to achieve these ends tacitly:

   D       =.   foo`bar`baz 
   t       =.   D / (@:])  NB. Here's our "over" (/)

   over    =.  [^:(D -: ]) L: (L.D) & (5!:1<,'t')
   allOver =:  (]^:[~ 1:`'' , over f.)~


   3 4 5 6 allOver"1~ (A.~i.@!@#) *`+`-       NB. Note the "1
9 _21 _1 _23 _41 _31

I warned you

Without getting into too much detail, the trick here is using the verb ]^:[ to allow ^: to execute an arbitrary atomic representation as input.

That is, some_atomic_rep f^:[ data turns into f^:some_atomic_rep data, which, for a suitable atomic rep, can execute anything at all, while using all the argument-processing goodness available to verbs (in particular, rank).

The rest is just an elegant (read: lazy) way to turn your gerundial inputs (whichever parts you make available to the verb with rank or other argument-selection mechanisms) into an atomic rep suitable for a right-hand argument to ^:.

The meat of it is we have the template D / (@:]) and we replace D with the gerund of your choice (the @:] is necessary because by the time the gerund gets executed, it'll have two inputs: your actual input, d, as well as itself, D)4.

Lasciate ogne speranza

To visit the Ultima Thule of these wicked follies, check out the discovery of dont in J, which is just like do (".), except ... really, you shouldn't.


¹ As a quick example: puzzle out what this would mean for precedence between wordclasses.

² Having said that, Jose "Pepe" Quintana, the leader of the underground J club F^4 (The Fully Fixable Functional Faction), once found a backdoor that actually did allow operators to take other operators as inputs. See this message in the "J Myths Puzzles" thread from 2008 (scroll past all the spoiler-hiding blank lines). Of course, once he mentioned it, Roger took notice, and immediately plugged the gap.

³ The way I once put it was "Yes, dcog is ugly, but I like to think of it as Messiah Code: it's ugly so that other code doesn't have to be. A sponge for sin".

4 Take note, the template gerund foo`bar`baz can be anything you like, of any length, using any names. It doesn't matter. What does matter is that the names you use are either proverbs or undefined (which the interpreter treats like proverbs, by design). Using pronouns or pro-operators will break stuff. Alternatively, you could use another kind of noun, like simply __ or something (which I find mnemonic for fill in the ____).

Upvotes: 2

bob
bob

Reputation: 4302

ms=.*`+`-     NB. list of gerunds
d =.3 4 5 6   NB. some data
allms=. (A.~i.@!@#) ms

I'd start by "treating my verbs like data" using strings to represent the gerunds

*`+`-

append the '/'character and then use 128!:2 (Apply) which takes a string describing a verb as its left argument and applies it to the noun that is its right argument. of course to do this you need to make allms into verb strings.

That can be done using:

   [ ger=. ,&'/' @ }: @ (1j1 #!.'`' ;)"1 allms
*`+`-/
*`-`+/
+`*`-/
+`-`*/
-`*`+/
-`+`*/

Then using 128!:2 (Apply)

   ger  128!:2 d
9 _21 _1 _23 _41 _31

As a one line tacit verb

   gvt=. ,&'/'@ }:@(1j1 #!.'`' ;)"1 @: [ 128!: 2 ] 
   allms gvt d
9 _21 _1 _23 _41 _31

I rarely play these games, so I am not saying this is the best approach, but it works.

Upvotes: 1

Related Questions