Applying an adverb to a list of gerunds
Asked Answered
S

2

4

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.

Salic answered 9/7, 2017 at 20:21 Comment(4)
@DanBron, cleanup on aisle Jonah!Salic
Haha. This is actually a really well-trodden area in J. Let's of discussions on this topic, many approaches. I am traveling work this week, so I don't have the cycles to post an answer, but in the interim, check out doog. Also, FYI, @username only sends a notification to people who have already interacted with the post. I found this question by my periodic sweep for J questions on SO.Reprieve
amazing. of course you’ve written a solution to this exact problem. i’ll be curious to hear the additional approaches and your thoughts on why doog or something like it isn’t built in. in the meantime thank you for the wonderful term “messiah code”. and on that note you may be able to answer this english.stackexchange.com/q/249608/25815Salic
There are fundamental syntactic reasons what you're describing here can't be built into J. Allowing operators (advs and conjs) 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 tradeoffs, in particular to simplicity and expressiveness (i.e. notational elegance). As a quick example: puzzle out what this would mean for precedence between nameclasses.Reprieve
R
2

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 ____).

Reprieve answered 10/7, 2017 at 21:33 Comment(6)
Amazing answer. Now you've got me going down multiple rabbit holes at once. What black magic is going on in your definition of gfy: (,'0') ((<@,)&<) ] (i turned on grouping to make sure i understood the parsing)Salic
@Salic That just turns a noun into its own atomic representation, so when you evoke the a.r., you get the noun back. In other words, the a.r. symbol for noun is 0. No, that's hardly the black magic here.Reprieve
Ah yes, nevermind i had a misunderstanding of what & was doing there, but I see now. I'll need some time to digest all the rest of it.Salic
@Salic Sorry if this just adds more rabbit holes to explore, but if you want to see a real magic &....Reprieve
The more the better! I have also posted a new question, if you have a few moments....Salic
Your services are needed here. bob says he thinks there's no answer... perhaps a challenge?Salic
P
1
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.

Phosphocreatine answered 10/7, 2017 at 6:34 Comment(6)
I appreciate the answer and it's always nice to see creative approaches, but I think the anonymous non-tacit verb from my OP is less hacky than string manipulation + eval. I mean, having to use points is ok. It just lacks the supreme elegance I look for in a J solution.Salic
Oh, I thought you were asking for a tacit verb. ;-) There are many times in J that explicit verbs are much better solutions. I'm glad that you prefer yoursPhosphocreatine
I would indeed like a tacit solution. Just not at the cost of replacing normal verb execution with string manipulation and eval. I think the answer to my question is "you can't do it," but I wanted to get an official confirmation from an expert, or else a demonstration of how it could be done.Salic
@Jonah, I believe a tacit solution would require append `:0, execute: ". or apply 128!:2. All of them usually produce a mess compared to a simple non-tacit verb.Tentation
@Tentation Nah, there are plenty of tacit ways to evoke gerunds directly. EG, there's the old dog (;.1)~(1:)(:6). This was better in the preJ601c days where e.g. +`*@{. would produce +@{.`(*@{.). But that feature was undocumented and eventually decommitted. I wrote a utility which emulates and extends it in post-601c interpreters. See my comment under the question. Of course, ;. isn't the only way to do this; if you haven't seen it before, it's worth reviewing this old overview of gerunds.Reprieve
@Dan, my point is that for this particular problem, a tacit solution is bound to be messy. At least it appears to me so, in contrast to a simple 4 :'x/y'.Tentation

© 2022 - 2024 — McMap. All rights reserved.