Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Evaluate a string as a verb in J

TL;DR

Given a string containing a (valid) verb, how do I obtain that verb without committing it to any variables? For example, say eval is that function; it should work like this:

   eval '+ @ >: @ %'
+@>:@%
   eval '+'
+

I only need it to be able to execute verbs and return them, but it would be cool to have arbitrary code be eval'd. (I do know about "., BTW.)


As a fun little experiment, I thought "hey, maybe I can make a verb that will transform a string of verbs into a train of verbs!" I know that I can use ;: to "word-ify" the string into J-verbs, like so:

   ]str =: '+ >: %'
+ >: %
   ;: str
┌─┬──┬─┐
│+│>:│%│
└─┴──┴─┘

So far, so good. Now, I just will primatively "join" them with '@' by using ,. ("ravel items"):

   '@' ,.~ > ;: str
+ @
>:@
% @

Flattening this yields:

+ @>:@% @

And finally, chopping off the trailing @ with }: yields + @>:@%, an uglier version of what I want, + @ >: @ %.

Now, this is all good and well, except for one thing: it's a string. Almost there! But not quite. I thought to myself, "Oh! ". would be perfect for this, it's basically eval." To my dismay, the docs read thus (emph mine):

".y executes the sentence y. If the execution results in a noun, the result of ".y is that noun; if the execution result is a verb, adverb, or conjunction, or if there is no execution result, the result of ".y is an empty vector.

Well, darnit. That won't work. I can certainly hack it together by defining a verb from within the string:

]verb =: , }: , '@' ,.~ > ;: str
+ @>:@% 
   'ret =: ' , verb
ret =: + @>:@% 
   ". 'ret =: ' , verb
   ret
+@>:@%

And this is all well and good, but rather clumsy, especially for J. The blow can be softened slightly with this is verb:

   is =: ".@(,&'=:'@,@[,}:@,@('@',.~>@;:)@])
   'G' is '+>:%'
   G
+@>:@%
   G 5
1.2

But only works if you're willing to commit the function to a variable.

So, my question stands: how do I convert a generic string holding a verb into a usable verb?

like image 723
Conor O'Brien Avatar asked May 12 '16 03:05

Conor O'Brien


1 Answers

Evoke gerund (`:) is what you want. Please refer to this short documentation for good examples. And in your case:

   str=: '+ @ >: @ %'
   (;: str) `:6
+@>:@%

You may want to review Tie (`) to understand this. ;: returns gerunds in our case (atomic representations), and m `: 6 converts gerund m to verb train.

Alternatively

   str =: '+ >: %'
   g =: verb def (str,' y')
   g 5
1.2

You can also try monad or dyad if you wish, e.g.

    2 (dyad def 'x * + % y') 5
0.4

Or to make a train, wrap str in parenthesis:

   2 (dyad def 'x (* + %) y') 5
10.4
like image 187
Dan Oak Avatar answered Sep 18 '22 12:09

Dan Oak