Where the Funcs Have No Name
Any self-respecting functional language has a way to create anonymous functions.
In YS there are more than one!
Today we'll talk about nameless functions, why they are useful, and how to create and call them.
What are anonymous functions good for?🔗
A functional language has lots of functions, and a lot of those functions take functions as arguments and/or return functions.
For example, the map
function takes a function and a list, and applies the
function to each element of the list.
Here we square the numbers 1 through 10.
$ ys -pe 'map sqr: 1 .. 10'
(1 4 9 16 25 36 49 64 81 100)
The sqr
function is part of the YS standard library.
So is cube
.
But what about quarq
(I just made that up) raising a number to the fourth power?
We could write a function for that:
$ ys -pe '
defn quarq(x): x ** 4
map quarq: 1 .. 10'
(1 16 81 256 625 1296 2401 4096 6561 10000)
But we could also write an anonymous function:
$ ys -pe 'map \(_ ** 4): 1 .. 10'
(1 16 81 256 625 1296 2401 4096 6561 10000)
The anonymous function syntax🔗
As you just saw, you create an anonymous function with the \( ... )
syntax.
Note
The \
is supposed to remind you of the λ
symbol in lambda calculus which
is all about anonymous functions.
Haskell also uses \
for anonymous functions.
The _
is a symbol for the first argument.
It can also be written as %1
Consider this example:
$ ys -pe 'apply \(%1 * %3 * %5): 1 .. 10'
15
We'll discuss apply
in a future post, but notice how we multiplied the first,
third, and fifth elements of the list 1 .. 10
without caring about the second
or fourth elements?
The fn
function🔗
The fn
function defines a function.
It's what defn
uses except that you don't need to give it a name.
These all do the same thing:
defn quarq(x): x ** 4
quarq =: \(_ ** 4)
quarq =:
fn(x): x ** 4
quarq =: fn([x] (x ** 4))
Higher order YS🔗
https://en.wikipedia.org/wiki/Higher-order_function
In mathematics and computer science, a higher-order function (HOF) is a function that does at least one of the following:
- Takes one or more functions as arguments (i.e. a procedural parameter, which is a parameter of a procedure that is itself a procedure),
- Returns a function as its result.
Let's write a function that returns a function.
Say we have a list of lengths in feet, meters, yards, or fathoms and we want to convert them to one of the other units.
We could write a function for each conversion or we could write a function that returns a function.
Convert a list of lengths from one unit to another
# convert,ys
!YS-v0
defn main(from to *nums):
each x nums:
converter =: converter-maker(from to)
say: "$x $from is $(converter x) $to"
foot =::
meters: 3.28084
fathoms: 6.0
feet: 1.0
yards: 3.0
defn converter-maker(a b):
fn(x):
x / foot.$b *: foot.$a
The converter-maker
function takes the names of 2 units and returns a function
that converts a number from the first unit to the second unit.
Let's run it:
$ ys convert.ys fathoms meters 2 3 5 7 11 13
2 fathoms is 3.657599882956804 meters
3 fathoms is 5.486399824435206 meters
5 fathoms is 9.143999707392009 meters
7 fathoms is 12.801599590348811 meters
11 fathoms is 20.11679935626242 meters
13 fathoms is 23.774399239219225 meters
Fathom that!
Ok, it's Summer hammock time.
See you tomorrow!
Note
If you made it this far, don't forget to add a reaction and please leave a comment if you have something to ask or say. I'd appreciate it!