5 comments

[ 5.5 ms ] story [ 33.9 ms ] thread
J acquires an equivalent to APL dfns. That's great news for the future in terms of terseness and flexibility!
APL has a complicated history in terms of function definitions: see https://aplwiki.com/wiki/Function_styles . Confusingly, these direct definitions have nothing to do with Iverson's 1974 direct definitions or those included in NARS in 1981: instead the name is presumably from the expansion of "dfn" as "direct function" (but it might also mean "dynamic function", no one knows).

However, these direct definitions don't have all that much in common with Dyalog's dfns either. The central points in common are the braced syntax, the fixed names like x and y for arguments, and the idea that a definition's type is determined by the argument names it contains. But another central idea of dfns is that they should use lexical scoping like Scheme: according to the document direct definition retains J's purely local scope, like Python. However, because they retain control structures, they will also have some expanded functionality relative to dfns, which remove them in favor of recursion and guards.

I didn't know about Iverson's DD, thanks for this historical perspective.

I always wondered why APL derivatives favoured imperative-style control flow operators, though. And now, it would seem that J is migrating towards an even more functional style with the F. primitive family. Wouldn't tail recursion be a useful addition to the language at this point? Or would it complicate the implementation too much?

I'd be interested in your opinion about that.

Hey, APL programmers preferred goto (→ or "Branch") until well into the 1980s. They've never really had a good grip on large-scale program structure. It's also worth noting that early J development was very invested in the tacit or point-free programming style, so a solid explicit style was perhaps considered less important than current usage would suggest.

I consider ALGOL-derived control structures to still be the most readable way to organize control flow. Tacit constructs like Agenda @. and Power ^: are good in small amounts but tend to require too much jumping around to read in larger programs. But control structures have their own problems, like a lack of flexibility for flows that don't quite match, scoping confusion (in for loops particularly), and the complicated continue/break/return hierarchy. I was recently surprised to find that first class functions and list literals in my own array language are enough to get a close approximation of control structures without these particular issues, and documented how it works at https://mlochbaum.github.io/BQN/doc/control.html .

Tail recursion isn't generally difficult to implement when it can be recognized, so if J hasn't added it (I don't know whether this is the case) it's probably just due to lack of interest in that style. J has a cool way to recurse in a tacit setting with $:, but I think recursion is seen more as a way to handle things like tree traversals that are obviously recursive than as a general control flow technique. J might also be able to move to lexical scoping, but it would mean that a variable defined in one function now shadows globals in the functions it contains, which could break some code. Maybe not a lot of code, because J's current explicit syntax strongly discourages nesting.

Maybe I'm mistaken, but I think recursion in J allows one to blow up the stack even when using $:

I agree that tacit control flow primitives can lead to confusing situations, but on the other hand they're faster and conceptually closer to the rest of the language.