Help / JforC / Parsing and Execution I
38. Parsing and Execution I
I hope your hunger for understanding will be enough to motivate you to read a couple of difficult chapters. If you do, you will learn something few J programmers know--what really happens when J executes a sentence. In this chapter we will analyze sentences from the top down, to get an idea for the order of execution. In the next chapter we will follow the interpreter as it alternately parses and executes sentences from the bottom up.
Since the understanding of parsing and execution that you have developed during your work so far is probably a bit inaccurate, we will work through examples of increasing complexity.
9!:3 (5) NB. Do this once to select simplified display &. &.
With only one word, there are no operands and nothing to execute, so the result of the sentence is the word itself: the conjunction &. .
The result of executing -:&.^., i. e. executing &. with -: and ^. as operands, is an anonymous verb. This anonymous verb will execute according to the definition of &., given its operands -: and ^. (i. e. -:&.^. y will be ^ -: ^. y ).
Note that the conjunction &. is executed without reference to the operand of the anonymous verb (indeed, in this case there is no such operand and the anonymous verb is the result of the sentence). We could assign the anonymous verb to a name, in which case it would no longer be anonymous (e. g. sqrt =: -:&.^.); without such an assignment we will refer to it here by the nickname av . The value of av is the verb described by -:&.^. .
-:&.^. 16 4
We know that this is executed as ^ -: ^. 16; let's see how that happens. Conjunctions are executed before verbs, so first -:&.^. will be executed to produce the anonymous verb we called av . Then av is executed with the operand 16 . av operates according to the definition of &. : it produces the same result as ^ -: ^. 16 (but it may use a different algorithm than executing ^ -: ^. 16 directly).
It appears that &. was executed twice: once to create av and then again during the execution of av . No, it was executed only once, to create av . av operates according to the definition of &., but it is av that is executing, not &. . The confusion arises because of the way the interpreter displays av . There is no better way to show a verb that performs the function -:&.^. than to show the way the verb was created, i. e. with the characters '-:&.^.', but you should think of this as an exhibition of the pedigree of av, and an assurance of its good behavior, rather than a list of functions to be executed. In fact, part of the reason for J's good performance comes from its recognizing functions that can be combined efficiently and providing customized routines to handle anonymous verbs that call for those combinations.
Confusion between a conjunction and the anonymous verb it produces is most likely when the conjunction is one you wrote using conjunction define or 2 :n . In most cases the text of the conjunction actually describes a derived verb, and it is natural for you to say 'the conjunction C is executed with operands u, v, and y' rather than the more accurate 'the anonymous verb created by the application of C to u and v is executed, with u and v available during the interpretation of the text of C and with y as the operand'. Such confusion is almost always harmless, but let's go through a few examples so you can see the layers of execution:
2 : 'u' 2 : 'u'
We execute 2 : 'u' and the result is an anonymous conjunction that we'll call ac1 . The display of ac1 shows where it came from. When ac1 is executed, its result will be its left operand.
+: (2 : 'u') -: +:
Here 2 : 'u' is executed first to produce ac1; then ac1 is executed with left operand of +: and right operand of -: . The result is an anonymous verb that we'll call av1; its value is the verb +: which was the left operand to ac1 .
+: (2 : 'u') -: 5 10
Remember, (2 : 'u') is a conjunction (the conjunction we have called ac1), and conjunctions are executed before verbs, so this is executed as (+: (2 : 'u') -:) 5, which becomes av1 5 . We execute av1 with the operand 5 . Monad +: doubles its operand, and the result is 10 .
We know that a conjunction can produce a conjunction result. That's how explicit conjunctions are formed: executing the conjunction : with left operand 2, as in 2 :n, produces a conjunction. There is nothing special about 2 :n : any conjunction is allowed to produce a conjunction result:
2 : '&' 2 : (,'&')
We execute 2 : '&' and the result is an anonymous conjunction that we'll call ac2 . The display of ac2 shows where it came from. (the , in the display of ac2 is harmless, a reminder that internally the anonymous entity resulting from m :n stores n as a list of characters.)
+: (2 : '&') -: &
We execute ac2 with left operand of +: and right operand of -: . The result is an anonymous conjunction that we'll call ac3 . ac3 is a conjunction because its value & (the last sentence executed by ac2) is a conjunction. Yes, & by itself can be a result: modifiers can return any primary part of speech (but try to return a conjunction from a verb and you will get an error).
Note that this is not the same as u&v : that would also be a valid return value from a conjunction, but u and v would be substituted and & would be executed to make the returned value an anonymous verb with the description u&v .
Make sure you see why the +: and -: disappeared. First, the conjunction : was executed with operands 2 and '&'; that produced a conjunction ac2 which was then executed with operands +: and -:; but the defining text of ac2 does not look at its operands; it simply produces the value & . So, the operands to ac2 disappear without a trace, and the result of the whole phrase is a conjunction with the value & .
2 (+: (2 : '&') -:) * 2&*
Continuing the example, we execute ac3 (which was just the conjunction &) with left operand 2 and right operand * . The result is the anonymous verb av2 which will execute as 2&* .
2 (+: (2 : '&') -:) * 5 10
Finally, we execute av2 with the operand 5, and get the result 10 .
Definitions That Refer To x or y
Explicit modifiers that refer to the operands of their derived verb (as x or y) come in for special treatment. A simple example is the conjunction defined by
2 : 'u v y' 2 : 'u v y'
We execute 2 : 'u v y' and the result is an anonymous conjunction that we'll call ac4 . You can't tell it from the display, but ac4 is a special kind of conjunction. Because it refers to y, the text of ac4 can be executed only as a verb (only then are x and y meaningful). The stored ac4 makes note of this fact.
+: (2 : 'u v y') - 5 _10
When ac4 itself is executed (as +: (2 : 'u v y') - here--since ac4 is a conjunction it is executed before its result is applied to the noun operand 5), the text of ac4 is not interpreted, as it was in our previous examples. Instead, the new anonymous verb av3 is created. av3 contains the defining text of ac4, along with the operands that were given to ac4 (+: and - here). When the verb av3 is executed as in the line above, the text of ac4 is finally interpreted, with the operands of ac4 (+: and - here) available as u and v, and the noun operands of av3 (5 here) available as y (and x if the invocation is dyadic); the result is the result of +: - 5 .