Using tacit recursion $: in gerunds: undocumented exception to the NuVoc description?

138 views
Skip to first unread message

Cameron Chandoke

unread,
Aug 21, 2024, 3:28:54 PMAug 21
to forum
Hello all, 

I am trying to discern whether the description of $: on NuVoc is a symmetrical rule for $: that includes the gerund case, or whether the gerund case is an undocumented exception.

The NuVoc page says $: stands for "the verb currently being executed". In the following code, I can see that, within "merge", $: stands for "merge" itself, rather than for (rec`:6):

   rec             =. ({.@] , }.@] $: [)`''          NB. gerund assignment
   merge       =. rec`:6~`rec@.(>&:{.)`]`[@.((+ 2&*)&(0 = #))
   mergesort=. (<.@-:@# ({. merge&$: }.) ])^:(1 < #)
   mergesort 10?.30
0 1 6 7 10 16 22 24 27 28
   merge
({.@] , }.@] $: [)~`({.@] , }.@] $: [)@.(>&:{.)`]`[@.((+ 2&*)&(0 = #))

This is the behavior I'd hoped for, but I'm unclear on why it works. Why does $: not instead get assigned the value ({.@] , }.@] $: [) during the (r=. verbPhrase`'') line (it doesn't get assigned any value until the gerund is evoked), whereas it does get assigned a value in the following sentence:

r=. {.@] , }.@] $: [        NB. verb assignment

The glossary's definition of "execution" is:

"The process of (1) replacing a verb and its arguments on the execution stack with the noun result from applying the verb to those arguments; or (2) from converting a fragment into a derived entity in accordance with the definition of the fragment, and replacing the fragment on the execution stack by a single synthetic word referring to the derived entity. Execution of a sentence proceeds generally right to left and ends with a single result which may be any type of entity."

In (r=. verbPhrase), where verbPhrase contains ($:), verbPhrase is executed prior to the execution of the (=.) (by the 2nd definition of "execute" given above). So this explains why $: is assigned the value of verbPhrase here. But by this definition,verbPhrase is also presumably executed prior to the execution of Tie (`) in the sentence (rec=. verbPhrase`'') (if my understanding is correct). But then why is $: not similarly assigned immediately to verbPhrase in the latter sentence? 

P.S. -- What is the standard way to markup J code in emails, if any?

Thank you all!

Henry Rich

unread,
Aug 21, 2024, 7:46:21 PMAug 21
to fo...@jsoftware.com
The value of $: is set in 3 places:

* when a thread is started, to the verb that is executed in the thread
* when a name is executed, to the value of the name
* when a the parser executes a verb on its noun arguments, to the value
of the verb

Those are the rules.  The rest is commentary; go and study it.

In r =. VerbPhrase, VerbPhrase itself is not executed.  Some other
execution produces VerbPhrase, but that is not an execution of
VerbPhrase on arguments.

In rec =. VerbPhrase`'', again VerbPhrase is not executed.  It is an
operand to ` but is not executed.

When    rec`:6~`rec@.(>&:{.)`]`[@.((+ 2&*)&(0 = #)) y  is executed, some
verb, say (rec) /is/ executed on arguments, but this execution is /not
by the parser/.  The execution comes from the execution of m@.v .  The
verb the parser executes is the entire anonymous verb
rec`:6~`rec@.(>&:{.)`]`[@.((+ 2&*)&(0 = #)) (with argument y): that big
verb becomes the value of $: .


I have spent hours agonizing over how to describe $: in NuVoc.  If
anyone can improve the description, please do.

Henry Rich
> To unsubscribe from this group and stop receiving emails from it, send
> an email to forum+un...@jsoftware.com.

Cameron Chandoke

unread,
Aug 24, 2024, 4:53:13 PMAug 24
to forum, Henry Rich
Wow, ok... very interesting and enlightening. I apologize for the late reply. Is there a simple example that demonstrates the thread rule? 
Being unfamiliar with spawning threads, I tried to verify it like this:

   rv=: $:@<:
   rv^:*t.2 ]10 
|stack error: rv
|       rv^:*t.2 ]10

   rv t.2^:*10
|stack error: rv
|       rv t.2^:*10

Based on the thread rule, I would've expected the result in one or both of the above cases to be the pyx (<0), since the entire derived verb rv^:* is being executed in the thread. 

Separately, does the "execution /by the parser/" distinction ever affect anything other than the value of $:? (This would affect how I would phrase it in the parser and $: pages).

As to $:'s description, I think simply adding the above 3 rules to the NuVoc page is mostly all that's needed, along with a link to the parser page, which would include an edit making the "execution /by the parser/" distinction, and its implications, a bit more explicit. I'm happy to make the edits once I'm clear on the 3 rules.

Henry Rich

unread,
Aug 24, 2024, 5:00:50 PMAug 24
to Cameron Chandoke, forum
Your rv immediately generates a stack error whenever it is executed.  It's an infinite recursion.  To show it you would need a verb that uses $: inside a task, and see that what comes before the task is not part of $:.

I think resetting $: is the only thing that differentiates execution by the parser from execution anywhere else, e. g. in a tacit verb.

Henry Rich

Cameron Chandoke

unread,
Aug 24, 2024, 5:58:52 PMAug 24
to Henry Rich, forum
Hmm... I'm not quite clear on what you mean by "what comes before the task". Do you merely mean "for $: within u within e.g. the phrase "(verb0 (u t.n) verb1) noun", the value of $: will be that of u, as opposed to the larger verb containing u", e.g.:

   (100 + [: > $:@<:^:*t.2@:(+&200))10    
100
So $: here is given the value ($:@<:^:*).

If this is what you mean, then, to summarize the scoping of ($:): letting Z denote the largest containing verb executed on noun(s) in the given sentence, the rules are that 
1.) the scope of $: within a given sentence is capped at the "earliest" by the smallest containing named verb. 
2.) if no such named verb exists that is different from Z itself, then the next opportunity for $:'s scope to be capped is by a containing verb that is passed as the u operand to (t.), within Z. In particular, this would mean that within the sentence '((+ $:@>:)^:(<&100)t.1 - $:@<:^:*t.2) noun', the two instances of $: refer to different verbs even though they both occur within a single containing verb being executed. 
3.) If neither (1) nor (2) is present in the sentence, then $:'s scope is that of Z (which, incidentally, is the /only/ containing verb to be executed by the parser itself). 

Have I understood correctly?

Also, do you have any insight as to whether the aforementioned gerund use of $: was anticipated by Ken Iverson, in order to factor out symmetric recursive phrases as in the "merge" verb in my original example? If so, it's even more admirably well thought out.

Henry Rich

unread,
Aug 24, 2024, 6:07:14 PMAug 24
to Cameron Chandoke, forum
I think you have it right.  In (2), the second $: would be a different verb even if it were not in a task.

I wish I knew what Ken anticipated, but I don't.

Henry Rich

Cameron Chandoke

unread,
Aug 24, 2024, 6:08:02 PMAug 24
to forum, Cameron Chandoke, forum, Henry Rich
Except I should've put the named verb case and the task case on the same level. That is, if $: occurs inside a named verb within the u operand to (t.), $:'s scope will be the value of said named verb (we could say the named verb "caps" $:'s scope here); and symmetrically, if $: occurs in u within the sentence 'namedVerb=: u t.2', then u will cap $:'s scope. Assuming my understanding is correct.

Cameron Chandoke

unread,
Aug 24, 2024, 6:14:44 PMAug 24
to forum, Cameron Chandoke, forum, Henry Rich
Right, good point about the 2nd (t.) not being needed for that case.

On a related note, what are your thoughts on adding a dedicated recursion scoping adverb to the language? Does it seem like potentially a bad/questionable idea for some reason, or seem merely unnecessary, or does it seem ok but low priority, or like a good idea? 

The motivation would be that its absence results in needing to break one's code into separate arbitrary lines in order to control the scope of $:, which feels clumsy relative to the rest of J.   

Raul Miller

unread,
Aug 24, 2024, 10:08:52 PMAug 24
to fo...@jsoftware.com, Cameron Chandoke, Henry Rich
Would this serve as a "dedicated recursion scoping adverb"?

scoped=: {{)a
m=. 'x(',(5!:5<'u'),')y'
3 :((}.m);':';m)
}}

If not, what should be different?

Thanks,

--
Raul

Cameron Chandoke

unread,
Aug 25, 2024, 1:03:06 AMAug 25
to Raul Miller, fo...@jsoftware.com, Henry Rich
Hmm... yes, that is it exactly. Cool! Thanks very much Raul.

Here it is rewritten in a single line (the simplest way I could find to construct it):
scoped=: {{ 3 :((}.;':';])('x(',5!:5@<@'u',')y'"_)u@[: ::]0)}}   NB. yes, this is an adverb
So, I have some further questions about this. I wouldn't have thought one could define this in J, but I suppose I should've been tipped off by this:
   rec=. $:@<:
   rec^:* f.
$:@<: (1 : 0)^:*
u y
:
x u y
)
When I had seen this result, I was unable to reason as to why it should work. And at the time, I attempted the obvious/naive implementation based on the above:
almostScoped=: {{ u{{u y}} : (u {{x u y}}) }}
But I saw that this didn't do what I wanted. So I mistakenly concluded that it was probably inaccurate, and was merely J's best attempt at communicating that the $: had been given the value of rec

So with that said... I'd like to ask:
1.) Why is almostScoped not equivalent to scoped? (Equivalently: why does almostScoped not accomplish the result given by rec^:* f. in the example above?) 
2.) By what thought process / prior experience did you realize how to write this scoped adverb?

Thanks very much,
Cameron

Cameron Chandoke

unread,
Aug 25, 2024, 1:10:20 AMAug 25
to Raul Miller, fo...@jsoftware.com, Henry Rich
I should clarify that by my second question, I really meant: how did you come to realize/suspect that [the approach used in writing scoped] would work, after seeing that almostScoped didn't accomplish the intended effect (assuming that you tried something similar first)?

Raul Miller

unread,
Aug 25, 2024, 6:27:13 AMAug 25
to Cameron Chandoke, fo...@jsoftware.com, Henry Rich
Hmm.... good point.

This also works, and is more concise:

scoped=: {{
u y
:
x u y
}}

I guess I had a dim memory of how f. worked and I've been using linear
representations in other contexts and dashed off a quick reply.

Thanks,

--
Raul

Cameron Chandoke

unread,
Aug 25, 2024, 12:19:33 PMAug 25
to forum, Raul Miller, fo...@jsoftware.com, Henry Rich, Cameron Chandoke
Right, I expected so but hadn’t tried it yet. But again the similar one-line version

{{ u{{u y}} : (u {{x u y}}) }}

does not work (I’m not sure what effect it has, if any), and I’m wondering why the two behave differently.

Raul Miller

unread,
Aug 25, 2024, 7:34:07 PMAug 25
to Cameron Chandoke, forum, Henry Rich
I am not completely confident I understand the change of events here,
but consider this:

h=: {{ (u{{
echo 5!:5<'u'
u y}}) : (u {{
echo 5!:5<'u'
x u y}}) }}


$:@<:^:* h@>: 3
|stack error

In other words, your inner definitions never get executed. Which means
we're getting recursion before anything gets executed.

And if I instead use

$:@([echo)@<:^:* h@>: 3

I get thousands of '3' lines, eventually ending with:

3
3
3
|stack error: echo

And, unfortunately, I can't use ([echo@(5!:5)@(<'$:')) to find out
what $: is bound to.

But, also, changing h to

h=: {{
(u f.{{
echo 5!:5<'u'
u y}}) : (u f.{{
echo 5!:5<'u'
x u y}}) }}

gives me the same behavior.

$:@<:^:* h@>: 3
|stack error

I tried using a breakpoint and the debug system to see if that would
show me what $: was, but...

e=: {{
echo y
'breakpoint here'
y
}}

$:@e@<:^:* h@>: 3

Even with a stop on every line of e, I don't get access to the
debugger until the stack is full (with the echo having emitted
thousands of lines). I think that's a bug in the j engine, so I'm
reluctant to speculate any further.

--
Raul

Jan-Pieter Jacobs

unread,
Aug 26, 2024, 1:37:00 AMAug 26
to fo...@jsoftware.com

Maybe the problem is trying to define everything on a single line. In a verb body, to separate monad and dyad chunks, the : should be on its own line; otherwise it's likely considered as conjunction : , which  will most likely not be what your looking for (see here https://code.jsoftware.com/wiki/Vocabulary/cor#2).


Jan-Pieter

Henry Rich

unread,
Aug 26, 2024, 8:54:51 AMAug 26
to Raul Miller, Cameron Chandoke, forum
It's not a JE bug.

   e
{{    echo y
   'breakpoint here'
   y}}

   l =.  $:@e@<:^:*

   l f.
$:@({{    echo y
   'breakpoint here'
   y}})@<:^:*

(l f.), which is what h uses, has been made anonymous by f., and you
have no breakpoints in it.

Henry Rich

Raul Miller

unread,
Aug 26, 2024, 11:08:07 AMAug 26
to Henry Rich, Cameron Chandoke, forum
Ah... careless of me. Thanks.

That said... removing the two instances of f. from h and retrying
$:@e@<:^:* h@>: 3 after opening the debugger and putting a stop on all
lines in e gave me this:

$:@e@<:^:* h@>: 3
|valence error: jdb_stackrep
| exl=.headerlines DEBUGNAMESUFFIX&(taketo,takeafter)&.>exl
|jdb_stackrep[:66]
coname''
┌──────┐
│jdebug│
└──────┘
JVERSION
Engine: j9.6.0-beta16/j64avx2/windows
Build: commercial/2024-08-09T21:00:58/clang-18-1-8/SLEEF=1
Library: 9.6.8
Qt IDE: 2.5.6/6.5.3(6.5.3)
OS Ver: Windows 11 Version 23H2 10.0.22631
Platform: Win 64
Installer: j9.6 install
InstallPath: c:/other/j9.6
Contact: www.jsoftware.com

And, after closing the debugger and hitting enter, my J session crashed.

Note also that changing the expression doesn't resolve this issue:

$:@e_base_@<:^:* h_base_@>: 3
|valence error: jdb_stackrep
| exl=.headerlines DEBUGNAMESUFFIX&(taketo,takeafter)&.>exl
|jdb_stackrep[:66]
exl
┌─────────┐
│ echo y│
└─────────┘
DEBUGNAMESUFFIX
d4B7g0

(Closing the debugger and hitting enter still crashes J.)

So... while I incorrectly criticized valid behavior in my previous
message, it coincidentally looks like there's still lightly treaded
(and unstable) ground herel

FYI,

--
Raul

Henry Rich

unread,
Aug 26, 2024, 11:14:18 AMAug 26
to Raul Miller, Cameron Chandoke, forum
Yes, that's a bug introduced by removal of (x m&v y). It's fixed in
ide/qt version 171; update your system using Package Manager.

Henry Rich

Raul Miller

unread,
Aug 26, 2024, 11:26:16 AMAug 26
to Henry Rich, Cameron Chandoke, forum
Huh... ok, updated.

Though it looks like i also falsely assumed that the recursive
instances of $: would show up as stack frames:

$:@e_base_@<:^:* h_base_@>: 3
3
3
13!:1''
|stop
* echo y
|e_base_[0]
| $:@e_base_@<:^:*h_base_@>:3


Anyways, given the crash, I'm wondering if it would help if $: was
slightly de-optimized to give some mechanism for introspecting its
current binding.

Thanks,

--
Raul

Henry Rich

unread,
Aug 26, 2024, 12:12:03 PMAug 26
to Raul Miller, Cameron Chandoke, forum
The crash is gone, right?  That makes it not a 'given'.

$: has never produced a stack frame.  Stack frames are created

* when debug is on and
** the parser starts
** a name is executed
** an explicit definition starts (9.6 only)
* when debug is off and there is an error (for postmortem debugging, 9.6
only)

Whatever.  Now comes the petitioner, asking for a way to know what $:
means.  There is no way to get that information out of the sentence as a
result.  It could perhaps be stored at some signal and queried later;
but then you could get only one value per console sentence.  And, that
value would have to be formatted as the signal in encountered, because
the components of the executing verb may disappear after they are used.

Given all that, I think the signal should cause the value of the
executing verb to be displayed on the console immediately.

What would the signal be?  I can imagine

* A new verb $:: that is $: with display of the linear rep of $:
* A new form $:!.r that is like $: with display of the selected rep of
$: (r must be an atom)
* A new conjunction (u 13!:n r) that would display u in representation r
(r could be a list but would probably be restricted to atoms)

13!:n is most general, but when would you ever use it except for looking
into $:?  I guess you might have a verb containing nouns, gerunds, etc.
that are not known until execution of the sentence. OTOH, 13!:n would
have to know about $: as a special case of u so that it would report the
value starting at the recursion point rather than simply showing '$:'.

Which of those appeals?  Or perhaps something else?  How often can you
see yourself using this?

Note: you would be able to write
dispu =: 13!:n (5)
and then use dispu in ($: dispu), because named modifiers that do not
refer to names are stacked by value and would not reset $: .

Henry Rich

Henry Rich

unread,
Aug 26, 2024, 1:32:21 PMAug 26
to Raul Miller, Cameron Chandoke, forum
Amendment: the conjunction 13!:n would display the representation of u
when it is applied to its u argument (i. e. during parsing) /EXCEPT/
when u is $:, in which case the display is deferred until the derived
verb is executed.

Henry Rich

Raul Miller

unread,
Aug 26, 2024, 1:54:49 PMAug 26
to Henry Rich, Cameron Chandoke, forum
The crash is gone. Crashes I don't understand make me uncomfortable,
but on reflection this was probably something in the way je and qtide
interacted, so it's probably fine now. (Thank you.)

As for my petition...

My thought was to treat $: as if it were a symbol table entry. So any
of the relevant 5!:n verbs would be able to extract its value. This
would save allocating any new "token space" for this issue. (But might
need a bit of extra setup work when $: is parsed?)

Failing that, I suppose a new foreign would be my next preference.

Thanks again,

--
Raul

Henry Rich

unread,
Aug 26, 2024, 3:21:15 PMAug 26
to Raul Miller, Cameron Chandoke, forum
The crash was a bug in handling error returns from the latent
expression, which by definition could be seen only when there is an
error in the Jqt debugger such as the one we triggered by disallowing (x
(m&v) y).  When I worked on the debugger many years ago before I had
access to the JE source, this bug caused me much grief.

The problem with trying to treat $: as a name is that it is not defined
at all when it is parsed.  The definition happens much later, when the
enclosing verb is finished.  The enclosing verb might not be executed,
and where would $: be stored then?  There is no symbol table that is
guaranteed to be valid, and even if it were, there might be many tacit
recursive definitions each having its own idea of what $: is; in fact
these could call each other, requiring a way to distinguish name
levels.  I don't think that's workable.

Henry Rich

Cameron Chandoke

unread,
Aug 26, 2024, 3:47:07 PMAug 26
to forum, Henry Rich, Cameron Chandoke, forum, Raul Miller
Sorry to jump backward a bit here, but I had meant to post this earlier and failed to do "reply all".

Yes, I was consciously using the Monad/Dyad conjunction (:) and assuming that it should effectively give the same result here as the ':' syntax used in multiline explicit (m : n) definitions.

   H=: {{  (u{{u y [ echo 'aaa'}}) : (u{{x u y [ echo 'aaa'}})  }}    NB. altered for simplicity

   $:@<:^:* H@>: 3                     NB. 'echo' never executes
|stack error
|       $:@<:^:*H@>:3

H's non-execution is independent of using ($:):

   (<: [ echo)^:*^:_ H@>: 3      NB. h's body was never executed; and the (@>:) was still applied
4
3
2
1
0

So it's not that H's operand merely executes before H can be bound to it; it's that H is ignored completely in the sentence. This seems likely to be a bug.

Separately, I'm observing that, for whatever reason, in order to limit the scope of ($:), we must use an explicit definition written in terms of x and/or y:

      $:@<:^:*{{u}}@>: 10               NB. adverb; not written in terms of x and/or y; no scoping effect
|stack error
|       $:@<:^:*{{u}}@>:10

   $:@<:^:*{{u y}}@>: 10                NB. adverb; written in terms of x and/or y; has scoping effect
0

   $:@<:^:*{{v u y}}(+&100)@>: 10   NB. conjunction; written in terms of x and/or y; has scoping effect
100

So apparently the given modifier, in order to enact scoping for $:, must be written in terms of x and y /at the outermost level/. While there are explicit definitions present within the body of 'H', at the outermost level its result expression {{(...) : (...)}}, or (f : g) for some f and g, gives a tacit verb. This would imply that there is no way to write a scoping adverb in terms of the ':' monad/dyad conjunction (which is of course different from the ':' found in the body following (m : 0)). But there was no reason to expect this prior to observing the above tests.

Interestingly, per the example in the NuVoc page for Fix (f.) , J901 gives this output:
      z =. $:@:<:^:*
      x =. 10 + z
      x f.
10 + 3 : '$:@:<:^:* y' :(4 : 'x $:@:<:^:* y')

... while in versions J902 and up, the output is:

10 + $:@:<:^:* (1 : 0)

u y
:
x u y
)

which implies that when this change was made, it was known that an explicit modifier written in terms of x and/or y has the effect of limiting the scope of the operand which contains ($:). I find that interesting since this fact isn't (yet) mentioned anywhere.

-- Cameron

Cameron Chandoke

unread,
Aug 26, 2024, 4:02:25 PMAug 26
to forum, Cameron Chandoke, Henry Rich, Raul Miller
Well, when we first saw that (scoped=: 1 :('u y';':';'x u y') worked as such, it was clear at that point that the implementors knew this, regardless of whether the current display format had been there from the beginning or had been added at some point. So the last point at the bottom of my previous message is moot.

-- Cameron

Cameron Chandoke

unread,
Aug 26, 2024, 4:12:00 PMAug 26
to forum, Cameron Chandoke, Raul Miller
On a side note, since the value of $: is seemingly unambiguous in all cases  so far, except for (... (... $: ...)H...), and now having seen that the strangeness of H's non-execution has nothing to do with $:'s presence, there may be less of a need/usefulness of a ($:)-querying functionality. I'm neutral about it.

-- Cameron

Henry Rich

unread,
Aug 26, 2024, 5:55:55 PMAug 26
to Cameron Chandoke, forum, Raul Miller
Yes, it was a bug.  There is code to prune the branches of structures like (v : v) : (v : v) and it was erroneously being applied to operator verbs.  Fixed in next beta.

Henry Rich

Raul Miller

unread,
Aug 26, 2024, 7:05:58 PMAug 26
to Henry Rich, Cameron Chandoke, forum
I think it's fine to report an empty result if $: is queried as a name
before it's defined. (Wouldn't a new foreign have the same
difficulty?)

And, I think that my proposal would require some sort of meta
name-class to be used for resolving references to $: - it's not like
the name itself is anything but unique.

Maybe I'm missing something?

Thanks,

--
Raul

Cameron Chandoke

unread,
Aug 28, 2024, 4:04:32 PMAug 28
to Raul Miller, Henry Rich, forum
TL;DR: NuVoc page updated to include exact rules for $: (Details section) and scoping control via f./gerunds (widen scope) and explicit modifiers (restrict scope). This added a fair amount of material. We may consider splitting off an ancillary page soon. 

———

"Details" section of NuVoc $: page is updated to include the exact value assignment rules for ($:). Also includes subsections on using f./gerunds to widen scope of ($:), and using an explicit modifier to limit the scope. 

As a precise and unambiguous description of the exact rules is necessarily elaborate, the older heuristics are kept at the top of the page, with a link to the exact rules at the bottom. 

The description of rules is longer than the concise description Henry gave in this thread because it includes the formerly omitted case of $:'s value being set when an operand is passed to an explicit modifier (e.g. Raul's scoping adverb); accounts for when one limiting case occurs within another; and provides an example.

This collectively added quite a bit of material to the page, although I feel good about its organization. 

I'd like to add material somewhere regarding how to effectively write APL’s tacit recursive recursive modifiers in terms of $: (in J, this would be a recursive verb that takes a gerund as one argument). This is something that any APL'er coming to J would wonder about, upon seeing that $: always refers to a verb.

At that point we may want to split the nuanced uses of $: into a separate ancillary page that is linked from the main $: page. 

Any thoughts welcome.

—Cameron

Cameron Chandoke

unread,
Aug 30, 2024, 7:24:49 PMAug 30
to forum, Cameron Chandoke, Henry Rich, forum, Raul Miller
So, to wrap up: does anyone understand why explicit modifiers, e.g. the {{u y}} adverb, have the scoping effect, i.e., the effect of making $: in its operand refer only to the operand itself, instead of referring to the outermost verb phrase that contains the derived verb u{{u y}}? Or does anyone have any idea how someone first discovered this fact prior to when the J engine was modified in J902 to display fixed scoped verbs using an explicit scoping adverb:  
   r=: $:@<:^:*
   r@>: f.
$:@<:^:* (1 : 0)@>:

u y
:
x u y
)
 
For example:
   ($:@<: [ echo)^:*{{u y}}@>: 3    NB. $: stands only for the u operand $:@<: [ echo)^:*
4
3
2
1
0
   ($:@<: [ echo)^:*@>: 3    
...
4
4
4
4
4
4
|stack error: echo
|       ($:@<:[echo)^:*@>:3

So far, for all I know, someone may have just discovered this as a bug, found it to be of use, and not reported it as a bug. And instead used it in J902 to display [an output for fixed scoped verbs] that would give a hint as to its scoping utility. Seems very strange.
 
Thanks,

-- Cameron


Henry Rich

unread,
Aug 30, 2024, 7:43:27 PMAug 30
to Cameron Chandoke, forum, Raul Miller
I don't understand what you are saying, or whether you're asking a question.

Henry Rich

Raul Miller

unread,
Aug 30, 2024, 8:57:27 PMAug 30
to Cameron Chandoke, forum, Henry Rich
If I understand your question, you're asking about what definition $:
gets bound to.

My understanding is that if a $: verb is a part of a train, or if it
is directly used by a built-in adverb or conjunction, then its working
definition includes that content. This also applies to gerunds of
such verbs if they're used as the gerund argument for something that
interprets the gerund as a verb. The result of any of these rules is a
$: verb.

Does this answer your question?

Thanks,

--
Raul

Cameron Chandoke

unread,
Aug 30, 2024, 11:15:11 PMAug 30
to forum, Raul Miller, forum, Henry Rich, Cameron Chandoke
Ah, I apologize for not being more clear. My question is: in both of the following verbs
 
$:@<:^:*@>:

and 

$:@<:^:*{{u}}@>:

the $: stands for the entire derived verb. But in 

$:@<:^:* {{u y}}@>:

the $: stands only for the u operand ($:@<:^:*). Why is this the case?

Thanks, 

-- Cameron

Henry Rich

unread,
Aug 30, 2024, 11:40:03 PMAug 30
to Cameron Chandoke, forum, Raul Miller
Wow.  Let me say, some things should be left undocumented.  That is almost as good as leaving them undefined.  Here: why would anyone write {{ u }} for a dollar when they could write ]: for a dime?  I say this having spent years trying to document JE, so I know where you're coming from.

I cut any corner, shave any cycle, tighten any branch that I can.  I want to make users forget that there is an interpreter, and get the performance as close as possible to compiled code.

That's why there is a special path in the parser for one-word sentences.  The full parser doesn't run; it just does the minimum required to resolve the value of the one word.  The case comes up a lot, usually for the result of a sentence or the value of an if. block.

Stacking/unstacking $: is not part of that minimum.  It's not an exception, because {{ u }} doesn't execute anything.

I could have said, {{ u }} is not an execution from the parser, and that would be the end of it.  Instead I gave you a deeper look; but please don't document it anywhere.  Who would benefit?

Henry Rich

Cameron Chandoke

unread,
Aug 31, 2024, 3:07:24 PMAug 31
to Henry Rich, Raul Miller, forum
I merely meant that I wasn't understanding why {{u y}} limits [$: within u] to stand only for u, as opposed to standing for the outermost verb phrase in the sentence. I had mentioned {{ u }} only to demonstrate that apparently [x and] y must be mentioned in order for $: to be limited to the u operand. Partly thanks to a hint in your reply, I now understand this dynamic:

It's because within the explicit adverb's private namespace, u is /just a named verb like any other/. And within the adverb's body, 'u y' is an execution, causing [$: within u] to be executed and thus assigned a value (namely, that of u). 

By contrast, {{ u }} (or e.g. {{5 + u}}; it need not be a one-word sentence) does not limit [$: within u] to stand only for u, because within the adverb's body, the named verb 'u' is not executed on nouns, as you pointed out. By the time that the verb derived from the modifier is executed, the modifier's namespace has disappeared. So in the phrase (... $: ...){{ u }}@>: the verb 'u' is never executed on nouns; only an anonymous derived verb is executed. As such, the $: within it is assigned to the outermost verb phrase that contains the verb derived by the adverb.

I suspect that the above dynamics were so obvious to you that you didn't realize that I might be missing them. Anyway, I now understand all this, and your reply helped.

I agree that there would be no point in documenting the special path in the parser, as that should have no effect on any behavior that the user would see.

Thanks,

Cameron


Henry Rich

unread,
Aug 31, 2024, 3:14:29 PMAug 31
to Cameron Chandoke, Raul Miller, forum
No, the behavior of {{ u }} wasn't obvious to me at first.  When I realized it wasn't an execution it all made sense.  You have it all right.

The exact statement would be that $: is set when there is an execution using lines 1-3 of the parsing table.  (5 + u) executes using line 6.

Henry Rich

Raul Miller

unread,
Aug 31, 2024, 8:53:31 PMAug 31
to Henry Rich, Cameron Chandoke, forum
"The exact statement would be that $: is set when there is an
execution using lines 1-3 of the parsing table. (5 + u) executes
using line 6."

I'm not sure that that identifies the binding used for $: (especially
in the context of sentences which use both : and $:).

--
Raul
Reply all
Reply to author
Forward
0 new messages