BIRDS: combinators in (B) '75
Smullyan's birds, written in APL with execute, read as a literate program
Table of Contents
- Birds and combinators
- The Thrush: calling a function by name
- Birds on values: the Idiot and the Kestrel
- The Kite: a bird made of two others
- Two functions at once: the Bluebird and the Starling
- One function, two ways round: the Cardinal and the Warbler
- The Mockingbird: a function applied to itself
- The Sage: recursion without a name
- What is still missing
- The workspace's own tour
- The workspace file
This is the (B) '75 BIRDS workspace from sw-apl's library 1, written as
a literate program: the prose and the code in the order a reader meets
them, rather than the order the file keeps them. Every function is
here, and the last section puts them together into the workspace file,
ws/lib1/BIRDS.b-75.apl.ws, byte for byte – tangling this document
writes that file. Every example below was run by sw-apl and its result
recorded under it; in the sw-apl in your browser, )LOAD 1 BIRDS in
the (B) tab gives the same answers.
Birds and combinators
A combinator is a function of functions. The Bluebird takes two functions and composes them; the Mockingbird takes a function and applies it to itself. Raymond Smullyan's To Mock a Mockingbird (1985) made each combinator a bird, and the names have stuck.
APL is a language of functions, but in the APL of 1970 a function
could not be handed to another: an argument is always an array. The
(A) '70 BIRDS gets as far as that allows, over a table of primitives.
(B) '75 has what makes the rest possible: execute, ⍎, which runs
a character vector as a line of APL.
⍎'2+3'
5
So in (B) a bird is given a function by its name – its glyph, or the name of a defined function – as characters, and calls it by building a line around the name and executing it. Nothing else is needed, and no table stands between the bird and the function: any function will do, primitive or defined.
The Thrush: calling a function by name
The Thrush is the pattern every bird follows, so it comes first.
X T F applies F to X: it catenates the name and ' X' and
executes the line.
∇R←X T F R←⍎F,' X' ∇
The line runs inside T, where X is T's own argument, so the
function named applies to the value T was given. A glyph is a name:
5 T '⍳'
1 2 3 4 5
and so is a defined function's name. FACT is the usual recursive
factorial, which the workspace keeps as a function to give to birds:
∇R←FACT N →(N>1)/MORE R←1 →0 MORE:R←N×FACT N-1 ∇
6 T 'FACT'
720
Birds on values: the Idiot and the Kestrel
Two birds apply nothing, so they need no execute. The Idiot gives back its argument, and the Kestrel keeps its left argument whatever its right one is.
∇R←I X R←X ∇
∇R←X K Y R←X ∇
I 42 7 K 9 'KEEP' K 1 2 3
I 42
42
7 K 9
7
'KEEP' K 1 2 3
KEEP
The Kite: a bird made of two others
Smullyan makes the Kite from the Kestrel and the Idiot: it is K I,
the Kestrel given the Idiot, and it keeps its right argument. In
(B) that construction can be written as he wrote it. 'I' K X is the
name 'I', whatever X is, and that name applied to Y is Y:
∇R←X KI Y ⍝ K GIVEN THE IDIOT: 'I' K X IS 'I', AND THAT NAME, APPLIED TO Y, ⍝ IS Y. R←⍎('I' K X),' Y' ∇
7 KI 9
9
Two functions at once: the Bluebird and the Starling
The Bluebird composes: FG B X is F G X. An APL function has at
most two arguments, and one of them is X, so both functions come in
one character vector, with a space between them since a name can be
longer than one character. The line ⍎ runs is then F G X itself:
∇R←FG B X ⍝ FG IS 'F G', TWO FUNCTIONS BY NAME OR GLYPH: F G X. R←⍎FG,' X' ∇
'⌽ ⍳' B 5 'FACT ⌈' B 3.2
'⌽ ⍳' B 5
5 4 3 2 1
'FACT ⌈' B 3.2
24
The Starling is X F G X: F between X and G X. With '+ ⌽',
each element is added to its mirror image:
∇R←FG S X ⍝ FG IS 'F G': X F G X. R←⍎'X ',FG,' X' ∇
'+ ⌽' S ⍳5
6 6 6 6 6
One function, two ways round: the Cardinal and the Warbler
The Cardinal flips the arguments of a dyadic function: F C Y Z is
Z F Y. It takes the two values as a pair, since F has the left
argument's place:
∇R←F C YZ R←⍎'YZ[2] ',F,' YZ[1]' ∇
'-' C 10 3
¯7
The Warbler gives a dyadic function the same argument on both sides:
F W X is X F X. HYP, the hypotenuse, is here to be given to it,
and × does as well:
∇R←F W X R←⍎'X ',F,' X' ∇
∇R←A HYP B R←((A*2)+B*2)*0.5 ∇
'HYP' W 3 '×' W 5
'HYP' W 3
4.2426
'×' W 5
25
The Mockingbird: a function applied to itself
The Mockingbird is λx.x x. A function is given here by its name, so
applied to itself means applied to its own name. SHOUT puts an
exclamation mark after its argument, and M 'SHOUT' is SHOUT given
'SHOUT':
∇R←M F ⍝ F APPLIED TO ITSELF: TO ITS OWN NAME. R←⍎F,' F' ∇
∇R←SHOUT X R←X,'!' ∇
M 'SHOUT'
SHOUT!
The Sage: recursion without a name
The Sage, Y, takes a function and gives back its fixed point, which
is recursion without the function ever naming itself. FSTEP is one
step of a factorial that calls itself only through its left argument,
SELF, a line of characters that says how:
∇R←SELF FSTEP N ⍝ ONE STEP OF THE FACTORIAL. IT NEVER NAMES ITSELF: SELF IS HOW. →(N>1)/MORE R←1 →0 MORE:R←N×⍎SELF,' N-1' ∇
The Sage supplies SELF: a quoted copy of the step's name followed by
Y, so that executing SELF with an argument goes round the Sage
again.
∇R←F Y X;SELF ⍝ THE FIXED POINT OF F. F IS DYADIC: ITS LEFT ARGUMENT IS HOW TO ⍝ CALL ITSELF, AS CHARACTERS, SO IT RECURSES WITHOUT ITS OWN NAME. SELF←'''',F,''' Y' R←⍎'SELF ',F,' X' ∇
'FSTEP' Y 6 FACT 6
'FSTEP' Y 6
720
FACT 6
720
APL evaluates an argument before the function that takes it, so a
Sage built by self-application alone would never stop building itself.
The strict fixed point, Z, delays the self-application by a step, and
that is what Y is here: the line in SELF is only characters until
FSTEP decides to run it.
What is still missing
With execute, every bird that APL of 1970 could not write is here.
NOTHERE says what (B) still lacks: a function as a value.
∇NOTHERE 'WITH EXECUTE, EVERY BIRD THAT APL\360 COULD NOT WRITE IS HERE:' 'THE MOCKINGBIRD, THE SAGE, AND K GIVEN I. WHAT IS STILL' 'MISSING IS A FUNCTION AS A VALUE.' '' 'A BIRD IS GIVEN A FUNCTION''S NAME, AND GIVES BACK A VALUE. IT' 'CANNOT GIVE BACK A FUNCTION: B RETURNS F G X, NOT THE NEW' 'FUNCTION F G, AND K GIVEN A FUNCTION CAN ONLY HAND BACK ITS' 'NAME. NOR CAN A DEFINED FUNCTION BE AN OPERAND: / AND ∘. TAKE' 'PRIMITIVES ONLY, IN THIS APL AS IN APL\360.' '' 'Y HERE IS ALSO Z, ITS STRICT FORM: APL EVALUATES AN ARGUMENT' 'BEFORE IT CALLS, SO THE SAGE IT CAN WRITE IS THE STRICT ONE.' ∇
NOTHERE
WITH EXECUTE, EVERY BIRD THAT APL\360 COULD NOT WRITE IS HERE: THE MOCKINGBIRD, THE SAGE, AND K GIVEN I. WHAT IS STILL MISSING IS A FUNCTION AS A VALUE. A BIRD IS GIVEN A FUNCTION'S NAME, AND GIVES BACK A VALUE. IT CANNOT GIVE BACK A FUNCTION: B RETURNS F G X, NOT THE NEW FUNCTION F G, AND K GIVEN A FUNCTION CAN ONLY HAND BACK ITS NAME. NOR CAN A DEFINED FUNCTION BE AN OPERAND: / AND ∘. TAKE PRIMITIVES ONLY, IN THIS APL AS IN APL\360. Y HERE IS ALSO Z, ITS STRICT FORM: APL EVALUATES AN ARGUMENT BEFORE IT CALLS, SO THE SAGE IT CAN WRITE IS THE STRICT ONE.
The workspace's own tour
A workspace in library 1 says what it holds when asked. DESCRIBE
lists the birds, and HOWBIRDS flies each one, showing the line as it
would be typed and then its answer.
∇DESCRIBE 'BIRDS -- COMBINATORS, AFTER THE BIRDS OF SMULLYAN''S' 'TO MOCK A MOCKINGBIRD. HOWBIRDS SHOWS THEM ALL. A FUNCTION' 'IS GIVEN TO A BIRD BY NAME OR GLYPH, AS CHARACTERS, AND' 'EXECUTE CALLS IT: ANY FUNCTION, PRIMITIVE OR DEFINED.' '' ' I X IDIOT X' ' X K Y KESTREL X, IGNORING Y' ' X KI Y KITE Y, IGNORING X: K GIVEN I' ' X T F THRUSH F X' ' FG B X BLUEBIRD F G X' ' F C Y Z CARDINAL Z F Y' ' F W X WARBLER X F X' ' FG S X STARLING X F G X' ' M F MOCKINGBIRD F F' ' F Y X SAGE THE FIXED POINT OF F, ON X' '' 'FG IS TWO FUNCTIONS, ''F G''. FSTEP, SHOUT AND HYP ARE THERE' 'TO BE GIVEN TO THE BIRDS. NOTHERE SAYS WHAT IS STILL MISSING.' ∇
∇HOWBIRDS ' I 42' I 42 ' 7 K 9' 7 K 9 ' 7 KI 9' 7 KI 9 ' 5 T ''⍳''' 5 T '⍳' ' ''⌽ ⍳'' B 5' '⌽ ⍳' B 5 ' ''FACT ⌈'' B 3.2' 'FACT ⌈' B 3.2 ' ''-'' C 10 3' '-' C 10 3 ' ''HYP'' W 3' 'HYP' W 3 ' ''+ ⌽'' S ⍳5' '+ ⌽' S ⍳5 ' M ''SHOUT''' M 'SHOUT' ' ''FSTEP'' Y 6' 'FSTEP' Y 6 ∇
HOWBIRDS
I 42
42
7 K 9
7
7 KI 9
9
5 T '⍳'
1 2 3 4 5
'⌽ ⍳' B 5
5 4 3 2 1
'FACT ⌈' B 3.2
24
'-' C 10 3
¯7
'HYP' W 3
4.2426
'+ ⌽' S ⍳5
6 6 6 6 6
M 'SHOUT'
SHOUT!
'FSTEP' Y 6
720
The workspace file
A saved workspace is APL that could have been typed: loading it runs
it. It opens with lines that say what it is – its modes, where it
came from, when it was saved, the settings it keeps – and names
itself; then come the functions, in the order )SAVE writes them,
which is by name.
⍝ sw-apl workspace. Re-executable APL: loading it runs it. ⍝!MODES (B) ⍝!SOURCE sw-apl -- written for this repository. MIT, (c) 2026 Michael A Wright. ⍝!SAVED 20.41.27 09/22/26 ⍝!LINK 16807 ⍝!ORIGIN 1 ⍝!DIGITS 5 ⍝!WIDTH 64 )WSID BIRDS
That order is the file's, not the reader's. The block below puts the pieces of this document together in it, and tangling the document writes the workspace:
<<workspace-header>> <<fn-b>> <<fn-c>> <<fn-describe>> <<fn-fact>> <<fn-fstep>> <<fn-howbirds>> <<fn-hyp>> <<fn-i>> <<fn-k>> <<fn-ki>> <<fn-m>> <<fn-nothere>> <<fn-s>> <<fn-shout>> <<fn-t>> <<fn-w>> <<fn-y>>
samples/80-birds-75.apl runs the same birds as a transcript, and
docs/birds.md sets them beside the (A) '70 workspace.