F# lambda
last modified May 17, 2025
This article explores how to work with lambda expressions in F# and their role in functional programming.
A lambda expression is an anonymous function that does not require an
explicit name. Lambda expressions are defined using the fun
keyword
and allow developers to create lightweight, inline functions that are often used
for short-lived operations. They enhance code readability and maintainability by
eliminating unnecessary function declarations.
Lambda expressions are particularly useful when passing functions as arguments, defining concise logic within higher-order functions, or streamlining simple computations. Since they are unnamed and typically defined within a specific context, they do not need to be reused across multiple locations in a program.
F# simple lambda
In the following example, we define a simple lambda.
let inc x = x + 1 let v = inc 90 printfn "%d" v let r = (fun x -> x + 1) 100 printfn "%d" r
The program contains a simple function and a lambda.
let inc x = x + 1
This is a definition of a function called inc
, which increments its
parameter.
let v = inc 90 printfn "%d" v
The inc
function is called and the result is printed.
let r = (fun x -> x + 1) 100
A lambda function is defined and immediately called. The function is anonymous and cannot be reused.
λ dotnet fsi main.fsx 91 101
F# lambda with high-order functions
Lambdas are often passed to high-order functions to define predicates.
let vals = [ 2; 1; -5; 8; 9; -2; 0; 5; 4 ] let res = List.map(fun e -> e * 2) vals printfn "%A" res let res2 = List.filter(fun e -> e < 0) vals printfn "%A" res2
In the example, we use two lambdas to create predicates for
List.map
and List.filter
functions.
λ dotnet fsi main.fsx [4; 2; -10; 16; 18; -4; 0; 10; 8] [-5; -2]
F# lambda argument types
The argument types are provided within round brackets, separately for each argument.
let msg = (fun (name: string)(age: int) -> $"{name} is {age} years old") "John Doe" 34 printfn "%s" msg
We have a lambda expression with two parameters: one string and one integer.
The arguments and their types are defined in ()
brackets.
λ dotnet fsi main.fsx John Doe is 34 years old
F# lambda with let binding
We can use a let binding in a lambda.
let names = [ "John Doe" "Lucy Smith" "Benjamin Young" "Robert Brown" "Thomas Moore" "Linda Black" "Adam Smith" "Jane Smith" ] names |> List.sortBy (fun e -> let a = e.Split(" ") in Array.get a 1) |> printfn "%A"
In the program, we sort a list of names by surnames.
|> List.sortBy (fun e -> let a = e.Split(" ") in Array.get a 1)
We split each name by a space and then retrieve the second element of the split.
λ dotnet fsi main.fsx ["Linda Black"; "Robert Brown"; "John Doe"; "Thomas Moore"; "Lucy Smith"; "Adam Smith"; "Jane Smith"; "Benjamin Young"]
F# lambda closure example
Lambdas can capture variables from their surrounding scope, creating closures. This allows the lambda to remember and update state between calls.
let makeCounter () = let mutable count = 0 fun () -> count <- count + 1 count let counter = makeCounter () printfn "%d" (counter ()) // 1 printfn "%d" (counter ()) // 2 printfn "%d" (counter ()) // 3
In this example, makeCounter
returns a lambda that increments and
returns a private counter. Each call to counter
increases the
value, demonstrating how lambdas can form closures over local variables.
λ dotnet fsi closure.fsx 1 2 3
In this article, we explored the fundamentals of lambda expressions in F# and their practical applications in functional programming.