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