Featured image of post F# Code Snippets

F# Code Snippets

Collected Useful F# Code Snippets

Common F# Code Snippets

1. Printing to the Console

1
printfn "Hello, world!"

No need for Console.WriteLine, just a simple printfn and you’re done!

2. Defining a Function

1
2
let square x = x * x
printfn "%d" (square 5) // Outputs: 25

Functions are first-class citizens in F#, and defining one is a breeze.

3. Piping Data (|> Operator)

1
2
3
let square x = x * x
let result = 5 |> square |> string
printfn "%s" result // Outputs: "25"

Piping makes function composition elegant and clean.

4. Pattern Matching

1
2
3
4
5
6
7
let describeNumber x =
    match x with
    | 0 -> "Zero"
    | 1 -> "One"
    | _ -> "Something else"

printfn "%s" (describeNumber 42) // Outputs: "Something else"

Forget those clunky if-else chains. Pattern matching is the way to go!

5. List Comprehensions

1
2
3
let numbers = [1..5]
let squaredNumbers = [for n in numbers -> n * n]
printfn "%A" squaredNumbers // Outputs: [1; 4; 9; 16; 25]

Simple, readable, and efficient.

6. Recursive Functions

1
2
3
4
5
let rec factorial n =
    if n <= 1 then 1
    else n * factorial (n - 1)

printfn "%d" (factorial 5) // Outputs: 120

Because recursion is the functional way!

7. Tuples and Destructuring

1
2
3
let person = ("Alice", 30)
let (name, age) = person
printfn "%s is %d years old." name age

Tuple unpacking makes handling grouped data a breeze.

8. Records (Lightweight Data Structures)

1
2
3
type Person = { Name: string; Age: int }
let bob = { Name = "Bob"; Age = 25 }
printfn "%A" bob // Outputs: { Name = "Bob"; Age = 25 }

Simple, structured data without the C# verbosity.

9. Option Type (No More Nulls!)

1
2
3
4
5
6
7
let divide a b =
    if b = 0 then None
    else Some (a / b)

match divide 10 2 with
| Some result -> printfn "Result: %d" result
| None -> printfn "Cannot divide by zero!"

F# says “nope” to nulls, and we love it.

10. Asynchronous Code

1
2
3
4
5
6
7
8
open System.Threading.Tasks

let asyncExample = async {
    do! Async.Sleep 1000
    printfn "Task Complete!"
}

Async.Start asyncExample

11. Sequences (Lazy Evaluation)

1
2
let infiniteNumbers = Seq.initInfinite (fun x -> x * x)
printfn "%A" (infiniteNumbers |> Seq.take 5 |> Seq.toList) // Outputs: [0; 1; 4; 9; 16]

Need an infinite list but don’t want to destroy your RAM? Sequences to the rescue!

12. Higher-Order Functions

1
2
3
let applyTwice f x = f (f x)
let double x = x * 2
printfn "%d" (applyTwice double 3) // Outputs: 12

Functions that take functions and return functions? Welcome to functional programming!

13. Discriminated Unions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
type Shape =
    | Circle of float
    | Rectangle of float * float

let area shape =
    match shape with
    | Circle r -> System.Math.PI * r * r
    | Rectangle (w, h) -> w * h

printfn "Circle area: %f" (area (Circle 5.0)) // Outputs: Circle area: 78.54

A clean and powerful way to model data variations.

14. Using the map Function

1
2
3
let numbers = [1..5]
let squared = numbers |> List.map (fun x -> x * x)
printfn "%A" squared // Outputs: [1; 4; 9; 16; 25]

Apply a function to every element of a list with zero fuss.

15. Folding (Reduce in Other Languages)

1
2
let sum = List.fold (fun acc x -> acc + x) 0 [1..5]
printfn "%d" sum // Outputs: 15

Folding is just a fancy way of saying “reduce everything to a single value.”

16. Working with Dictionaries

1
2
let dict = dict ["one", 1; "two", 2; "three", 3]
printfn "%d" (dict.["two"]) // Outputs: 2

Need key-value pairs? Dictionaries got you covered.

17. Using try...with for Exception Handling

1
2
3
4
5
6
7
8
9
let safeDivide a b =
    try
        Some (a / b)
    with
    | :? System.DivideByZeroException -> None

match safeDivide 10 0 with
| Some result -> printfn "Result: %d" result
| None -> printfn "Oops! Division by zero."

Because sometimes, life (and division) throws you an error.

18. Using async Workflows

1
2
3
4
5
6
let asyncJob = async {
    do! Async.Sleep 1000
    printfn "Done sleeping!"
}

Async.Start asyncJob

Non-blocking, super clean asynchronous programming.

19. Partial Application

1
2
3
let multiply x y = x * y
let double = multiply 2
printfn "%d" (double 10) // Outputs: 20

Fix arguments ahead of time for ultimate function reusability!

20. Using Seq.filter for Filtering Data

1
2
3
let numbers = [1..10]
let evens = numbers |> List.filter (fun x -> x % 2 = 0)
printfn "%A" evens // Outputs: [2; 4; 6; 8; 10]

Elegant, readable, and functional filtering.

21. Function Composition (>> Operator)

1
2
3
4
5
let add2 x = x + 2
let multiply3 x = x * 3
let addThenMultiply = add2 >> multiply3

printfn "%d" (addThenMultiply 4) // Outputs: 18

Think of >> as piping without explicit arguments. Super clean!

22. Defining Custom Operators

1
2
let (++) x y = x + y * 2
printfn "%d" (5 ++ 3) // Outputs: 11

Why use boring old operators when you can make your own?

23. Using the yield Keyword in Sequences

1
2
3
4
5
6
let numbers = seq {
    yield 1
    yield 2
    yield! [3; 4; 5]
}
printfn "%A" (numbers |> Seq.toList) // Outputs: [1; 2; 3; 4; 5]

yield! lets you expand another sequence inside your own.

24. Type Providers for Easy Data Access

1
2
3
4
5
6
7
8
#r "nuget: FSharp.Data"
open FSharp.Data

let csv = CsvProvider<"Name,Age\nAlice,30\nBob,25">
let data = csv.GetSample()

for row in data.Rows do
    printfn "%s is %d years old" row.Name row.Age

Type providers give you strongly-typed access to external data. No manual parsing required!

25. Asynchronous Parallel Computation

1
2
3
4
5
6
7
open System.Threading.Tasks

let task1 = async { return 5 }
let task2 = async { return 10 }
let combined = Async.Parallel [task1; task2]

Async.RunSynchronously combined |> printfn "%A" // Outputs: [|5; 10|]

Run multiple async tasks in parallel like a pro.

26. Memoization (Caching Function Results)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let memoize f =
    let cache = System.Collections.Generic.Dictionary<_, _>()
    fun x ->
        if cache.ContainsKey(x) then cache.[x]
        else
            let result = f x
            cache.[x] <- result
            result

let expensiveComputation = memoize (fun x -> x * x * x)
printfn "%d" (expensiveComputation 10) // Outputs: 1000

Memoization = automatic caching for expensive functions.

27. Active Patterns for Smart Matching

1
2
3
4
5
6
7
8
let (|Even|Odd|) x = if x % 2 = 0 then Even else Odd

let describeNumber x =
    match x with
    | Even -> "Even number"
    | Odd -> "Odd number"

printfn "%s" (describeNumber 5) // Outputs: Odd number

Active patterns let you create custom match cases for cleaner logic.

28. Infinite Lazy Sequences

1
2
3
4
5
let rec fibs a b = seq {
    yield a
    yield! fibs b (a + b)
}
printfn "%A" (fibs 0 1 |> Seq.take 10 |> Seq.toList)

Lazy evaluation lets you generate infinite sequences without crashing your machine.

29. Using MailboxProcessor for Actor-Based Concurrency

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let agent = MailboxProcessor.Start(fun inbox ->
    let rec loop () = async {
        let! msg = inbox.Receive()
        printfn "Received: %s" msg
        return! loop()
    }
    loop()
)

agent.Post "Hello, F#"

MailboxProcessor is a great way to handle message-based concurrency.

30. Dependency Injection with Partial Application

1
2
3
4
5
6
7
let log message = printfn "Log: %s" message
let add x y = x + y
let addWithLogging = fun x y ->
    log (sprintf "Adding %d and %d" x y)
    add x y

printfn "%d" (addWithLogging 3 7) // Outputs: Log: Adding 3 and 7, then 10

Inject dependencies (like logging) into your functions using partial application.


References