Repository navigation
[feature request] first class verbs #116
Description
The idea of "first class verbs" or more commonly "first class functions" is a general principle that gives a language the following features:
- closures (may be used as classes or namespaces in OOP, analogous to locales in J)
- higher order functions (adverbs and conjunctions in J)
- ability to pass functions around (gerunds in J)
- ability to define new control structures in the language itself
Today some of the features of first class verbs already exist in J, but have limitations and require verbose syntax.
I'll put some examples below to show how this could look in future J code.
accept verbs as parameters
This is awkward in J, as it requires first turning the verb into a gerund with ` (tie), and then using `: (evoke gerund) to turn it back into a verb:
({{2<y}}`'') {{ ((x`:6) y) # y }} i.9
3 4 5 6 7 8First class verbs simplifies the above example to this:
NB. proposed change
{{2<y}} {{ (x y) # y }} i.9
3 4 5 6 7 8NOTE: The phrase {{ x y }} is currently a syntax error, so adding this feature would not break any existing code.
return verbs as values
This feature is often called a "closure" in other programming languages, because the inner scope "closes over" (inheriits) the variables from the outer scope.
Similar to the previous example, now returning a verb from another verb:
f1 =: {{
s =. y
({{ s + y }}`'') }}
((f1 3)`:6) 10
13However, I think gerunds may be buggy (perhaps only inside{{}}), because executing it with different arguments gives an unchanging result:
NB. buggy behavior
((f1 3)`:6) 1
4
((f1 99)`:6) 1
4The above should work like this instead:
NB. correct behavior
((f1 3)`:6) 1
4
((f1 99)`:6) 1
100Proposed enhancement: returning a verb and using that verb can work like this:
NB. proposed change
f1 =: {{
s =. y
{{ s + y }} }}
(f1 3) 10
13
(f1 4) 10
14Currently, the explicit definition above is not a syntax error, but running (f1 3) is an error:
|noun result was required: f1
| {{s + y }}
I don't think adding this feature (return verbs from verbs) would break any code, but I'm not sure.
rationale
- First class verbs are a more flexible alternative to
`:, because they allow users to define their own composition patterns (currentlym`:naccepts0,3or6as values ofn, with 3 hard-coded behaviors). - Treating verbs as regular values removes the verb/adverb/conjunction distinction. Many adverbs and conjunctions can be written using only first class verbs. This might make J easier to learn.
- First class verbs can emulate locales, but with lexical scope (which arguably makes programs easier to debug). For example, it is possible to emulate OOP-style classes with mutable closures.
- Non-breaking: This proposal does not explicitly add any syntax to J, but rather gives meaning to syntax which is currently an error.
Activity
HenryHRich commentedon Nov 5, 2021
Allowing a verb to return a verb would affect the parser and the JE in general. If OTOH the result of a verb can be a noun gerund that is then executed as a verb, additionally there is the overhead of checking each result to see whether it can be executed.
The 'buggy behavior' is correct: s in the nested {{ }} is not inherited from the enclosing verb and is presumably a global left around in the author's session.
An idea to consider is a locale syntax that specifies a name in the caller's stack frame: s___1 to mean 's in the caller'. This would not help the nested-s issue, since the definition is not executed while the caller is in scope, but there might be some other uses for it.
hoosierEE commentedon Nov 5, 2021
Thanks Henry, that is a good point about performance. I like the idea of "only pay for what you use", so while I would be happy to pay a performance penalty for code which uses this feature, code which does not use the feature shouldn't pay its cost.
I did not realize that direct definition verbs can only access variables either in the global scope or their own scope. I see now that it's not a bug, so perhaps that will become a separate feature request.
I realized after writing my feature request that I should give more examples. Here's an example where a closure which can refer to variables from its parent scope:
J already has facilities (
coclassetc.) that allow creating a functionally-identical program:This may not be a great example, since there's not a huge difference syntactically - the closure is only a little shorter, and whether lexical scope is clearer is subjective.
When the (closure version)
s1goes out of scope, is erased, or overwritten, the interpreter could possibly automatically free boths1and itscount, whereas for objects created withconew, the programmer must "manually" usecodestroy__s1''.First class verbs are not essential for my work with J, but because they can mimic locales, classes, adverbs, and conjunctions with minimal syntax, I consider them a powerful tool of thought.