aboutsummaryrefslogtreecommitdiff
path: root/doc/functional.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/functional.md')
-rw-r--r--doc/functional.md18
1 files changed, 9 insertions, 9 deletions
diff --git a/doc/functional.md b/doc/functional.md
index edc20c5f..45614904 100644
--- a/doc/functional.md
+++ b/doc/functional.md
@@ -4,7 +4,7 @@ BQN boasts of its functional capabilities, including first-class functions. What
First, let's be clear about what the terms we're using mean. A language has *first-class functions* when functions (however they are defined) can be used in all the same ways as "ordinary" values like numbers and so on, such as being passed as an argument or placed in a list. Lisp and JavaScript have first-class functions, C has unsafe first-class functions via function pointers, and Java and APL don't have them as functions can't be placed in lists or used as arguments. This doesn't mean every operation is supported on functions: for instance, numbers can be added, compared, and sorted; while functions could perhaps be added to give a train, comparing or sorting them as functions (not representations) isn't computable, and BQN doesn't support any of the three operations when passing functions as arguments.
-Traditionally APL has worked around its lack of first-class functions with operators or second-order functions. Arrays in APL are first class while functions are second class and operators are third class, and each class can act on the ones before it. However, the three-tier system has some obvious limitations that we'll discuss, and BQN removes these by making every type first class.
+Traditionally, APL has worked around its lack of first-class functions with operators, that is, second-order functions. Arrays in APL are first class while functions are second class and operators are third class, and each class can act on the ones before it. However, the three-tier system has some obvious limitations that we'll discuss, and BQN removes these by making every type first class.
The term *functional programming* is more contentious, and has many meanings some of which can be vague. Here I use it for what might be called *first-class functional programming*, programming that makes significant use of first-class functions; in this usage, Scheme is probably the archetypal functional programming language. However, two other definitions are also worth mentioning. APL is often called a functional programming language on the grounds that functions can be assigned and manipulated, and called recursively, all characteristics it shares with Lisp. I prefer the term *function-level programming* for this usage. A newer usage, which I call *pure functional programming*, restricts the term "function" to mathematical functions, which have no side effects, so that functional programming is programming with no side effects, often using monads to accumulate effects as part of arguments and results instead. Finally, *typed functional programming* is closely associated with pure functional programming and refers to statically-typed functional languages such as Haskell, F#, and Idris (the last of which even supports *dependently-typed functional programming*, but I already said "finally" so we'll stop there). Of these, BQN supports first-class functional and function-level programming, allows but doesn't encourage pure functional programming, and does not support typed functional programming, as it is dynamically and not statically typed.
@@ -26,26 +26,26 @@ What does functional programming in BQN look like? How is it different from the
### Working with roles
-First, let's look at the basics: a small program that takes a function as its argument and result. The function `Lin` below gives a linear approximation to its function argument based on the values at 0 and 1. To find these two values, we call the argument as a function by using its uppercase spelling, `𝕏`.
+First, let's look at the basics: a small program that has functions as its argument and result. The function `Lin` below gives a linear approximation to its function argument based on the values at 0 and 1. To find these two values, we call the argument as a function by using its uppercase spelling, `𝕏`.
Lin ← {
v0 ← 𝕏 0
v0 + ((𝕏 1) - v0) Γ— ⊒
}
-We can pass it the exponential function as an argument by giving it the name `Exp` and then referring to it in lowercase (that is, in a value role). The result is a train that adds 1 to *e*-1 times the argument.
+We can pass it the exponential function as an argument by giving it the name `Exp` and then referring to it in lowercase (that is, in a subject role). The result is a train that adds 1 to *e*-1 times the argument.
Exp ← ⋆
Lin exp
(1 + (1.71828182845905 Γ— ⊒))
-As with all functions, the result of `Lin` has a value role. To use it as a function, we give it a name and then use that name with an uppercase spelling.
+As with all functions, the result of `Lin` has a subject role. To use it as a function, we give it a name and then use that name with an uppercase spelling.
expLin ← Lin exp
ExpLin 5
9.59140914229523
-A tricker but more compact method is to use the modifier `{𝔽}`, as the input to a modifier can have a value or function role but its output always has a function role.
+A tricker but more compact method is to use the 1-modifier `{𝔽}`, as the input to a modifier can have a subject or function role but its output always has a function role.
(Lin exp){𝔽} 5
9.59140914229523
@@ -69,12 +69,12 @@ Its call syntax is simpler as well. In other cases, however, the function versio
### Arrays of functions
-It's very convenient to put a function in an array, which is fortunate because this is one of the most important uses of functions as values. Here's an example of an array of functions with a reduction applied to it, composing them together.
+It's very convenient to put a function in an array, which is fortunate because this is one of the most important uses of functions as subjects. Here's an example of an array of functions with a reduction applied to it, composing them together.
{π•Žβˆ˜π•}Β΄ ⋆‿-β€Ώ(Γ—Λœ)
β‹†βˆ˜(-∘(Γ—Λœ))
-Like any function, this one can be given a name and then called. A quirk of this way of defining a function is that it has a value role (it's the result of the function `{π•Žβˆ˜π•}Β΄`) and so must be defined with a lowercase name.
+Like any function, this one can be given a name and then called. A quirk of this way of defining a function is that it has a subject role (it's the result of the function `{π•Žβˆ˜π•}Β΄`) and so must be defined with a lowercase name.
gauss ← {π•Žβˆ˜π•}Β΄ ⋆‿-β€Ώ(Γ—Λœ)
Gauss 2
@@ -85,9 +85,9 @@ Another, and probably more common, use of arrays of functions is to apply severa
⟨√, 2⊸∾, ⊒-β‹†βŸ© {π•Žπ•©}Β¨ 9
[ 3 [ 2 9 ] Β―8094.083927575384 ]
-The composition Choose (`β—Ά`) relies on arrays of functions to… function. It's very closely related to Pick `βŠ‘`, and in fact when the left operand and the elements of the right operand are all value types there's no real difference: Choose returns the constant function `π•—βŠ‘π•˜`.
+The 2-modifier Choose (`β—Ά`) relies on arrays of functions to… function. It's very closely related to Pick `βŠ‘`, and in fact when the left operand and the elements of the right operand are all data there's no real difference: Choose returns the constant function `π•—βŠ‘π•˜`.
- 2β—Ά"abcdef" "arg"
+ 2β—Ά"abcdef"β€Ώ"arg"
c
When the operands contain functions, however, the potential of Choose as a ternary-or-more operator opens up. Here's a function for a step in the Collatz sequence, which halves an even input but multiplies an odd input by 3 and adds 1. To get the sequence for a number, we can apply the same function many times. It's an open problem whether the sequence always ends with the repetition 4, 2, 1, but it can take a surprisingly long time to get thereβ€”try 27 as an argument.