Lambdas and Higher-Order Functions
Prerequisites: Currying and partial application
A lambda is a function without a name, written with fun:
let square = fun x -> x * x
printfn "%d" (square 4)
[1; 2; 3]
|> List.map (fun x -> x * 10)
|> printfn "%A"
16
[10; 20; 30]
let square x = x * x is just a shorter way of writing the first line.
Higher-order functions
A higher-order function takes a function as a parameter or returns
one. List.map is one; you can write your own:
let applyTwice f x = f (f x)
printfn "%d" (applyTwice (fun n -> n + 3) 10)
printfn "%s" (applyTwice (fun s -> s + "!") "hey")
let makeGreeter greeting =
fun name -> $"{greeting}, {name}!"
let hello = makeGreeter "Hello"
let hola = makeGreeter "Hola"
printfn "%s" (hello "Ada")
printfn "%s" (hola "Linus")
16
hey!!
Hello, Ada!
Hola, Linus!
applyTwice has the type ('a -> 'a) -> 'a -> 'a: its first parameter
is itself a function. makeGreeter returns a function that remembers
greeting — a closure.
Shorthand: _.Property
Since F# 8, _.Member is a shortcut for a lambda that reads a property
or calls a method:
["kiwi"; "banana"; "fig"]
|> List.map _.Length
|> printfn "%A"
["kiwi"; "banana"; "fig"]
|> List.map _.ToUpper()
|> printfn "%A"
[4; 6; 3]
["KIWI"; "BANANA"; "FIG"]
Operators are functions
Wrap an operator in parentheses to use it as a function:
printfn "%d" ((+) 2 3)
printfn "%d" (List.reduce (+) [1; 2; 3; 4])
printfn "%A" (List.map ((*) 2) [1; 2; 3])
5
10
[2; 4; 6]
Practice
Write a function compose3 f g h that returns a function applying f,
then g, then h. Use it to build a function that adds 1, doubles, and
converts to a string with a "#" in front. Apply it to 4.
Show solution
let compose3 f g h = f >> g >> h
let label = compose3 (fun x -> x + 1) (fun x -> x * 2) (fun x -> $"#{x}")
printfn "%s" (label 4)
#10