From 55c40e75dde0ddad39a305f29e036ec88c85babe Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Wed, 2 Dec 2020 14:45:59 -0500 Subject: Move problems.md to commentary folder --- docs/doc/functional.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/doc/functional.html') diff --git a/docs/doc/functional.html b/docs/doc/functional.html index 4a5b7495..7e3b3900 100644 --- a/docs/doc/functional.html +++ b/docs/doc/functional.html @@ -63,7 +63,7 @@

Another topic we are interested in is lexical scoping and closures. Lexical scoping means that the realm in which a variable exists is determined by its containing context (in BQN, the surrounding set of curly braces {}, if any) within the source code. A closure is really an implementation mechanism, but it's often used to refer to a property of lexical scoping that appears when functions defined in a particular block can be accessed after the block finishes execution. For example, they might be returned from a function or assigned to a variable outside of that function's scope. In this case the functions can still access variables in the original scope. I consider this property to be a requirement for a correct lexical scoping implementation, but it's traditionally not a part of APL: implementation might not have lexical scoping (for example, J and I believe A+ use static scoping where functions can't access variables in containing scopes) or might cut off the scope once execution ends, leading to value errors that one wouldn't predict from the rules of lexical scoping.

Functions in APL

This seems like a good place for a brief and entirely optional discussion of how APL handles functions and why it does it this way. As mentioned above, APL's functions are second class rather than first class. However, it's worth noting that the barriers to making functions first-class objects have been entirely syntactic and conceptual, not technical. In fact, the J language has for a long time had a bug that allows an array containing a function to be created: by selecting from the array, the function itself can even be passed through tacit functions as an argument!

-

The primary reason why APL doesn't allow functions to be passed as arguments is probably syntax: in particular, there's no way to say that a function should be used as the left argument to another function, as an expression like F G x with functions F and G and an array x will simply be evaluated as two monadic function applications. However, there's no syntactic rule that prevents a function from returning a function, and Dyalog APL for example allows this (so '+' returns the function +). Dyalog's OR is another interesting phenomenon in this context: it creates an array from a function or operator, which can then be used as an element or argument like any array. The mechanism is essentially the same as BQN's first class functions, and in fact ORs even share a form of BQN's syntactic type erasure, as a OR of a function passed as an operand magically becomes a function again. But outside of this property, it's cumbersome and slow to convert functions to and from ORs, so they don't work very well as a first-class function mechanism.

+

The primary reason why APL doesn't allow functions to be passed as arguments is probably syntax: in particular, there's no way to say that a function should be used as the left argument to another function, as an expression like F G x with functions F and G and an array x will simply be evaluated as two monadic function applications. However, there's no syntactic rule that prevents a function from returning a function, and Dyalog APL for example allows this (so '+' returns the function +). Dyalog's OR is another interesting phenomenon in this context: it creates an array from a function or operator, which can then be used as an element or argument like any array. The mechanism is essentially the same as BQN's first class functions, and in fact ORs even share a form of BQN's syntactic type erasure, as a OR of a function passed as an operand magically becomes a function again. But outside of this property, it's cumbersome and slow to convert functions to and from ORs, so they don't work very well as a first-class function mechanism.

Another reason for APL's reluctance to adopt first-class functions is that Iverson and others seemed to believe that functions fundamentally are not a kind of data, because it's impossible to uniquely represent, compare, and order them. One effect of this viewpoint is J's gerund mechanism, which converts a function to an array representation, primarily so that lists of gerunds can be created. Gerunds are nested arrays containing character vectors at the leaves, so they are arrays as Iverson thought of them. However, I consider this conversion of functions to arrays, intended to avoid arrays that contain "black box" functions, to be a mistake: while it doesn't compromise the purity of arrays, it gives the illusion that a function corresponds to a particular array, which is not true from the mathematical perspective of functions as mappings from an arbitrary input to an output. I also think the experience of countless languages with first-class functions shows that there is no practical issue with arrays that contain functions. While having all arrays be concrete entities with a unique canonical representation seems desirable, I don't find the existence of arrays without this property to be detract from working with arrays that do have it.

Functional programming in BQN

Reminder: I am discussing only first-class functional programming here, and not other concepts like pure or typed functional programming!

-- cgit v1.2.3