F# Language Samples

Essential F# programming examples for functional programming and .NET development

💻 F# Hello World fsharp

🟢 simple ⭐⭐

Basic F# Hello World program and fundamental functional programming concepts

⏱️ 20 min 🏷️ fsharp, functional programming, dotnet, beginner
Prerequisites: Basic programming concepts, Understanding of functional programming, .NET basics
// F# Hello World Examples

// 1. Basic Hello World
printfn "Hello, World!"

// 2. Hello World with let binding
let message = "Hello, World!"
printfn "%s" message

// 3. Hello World with function
let sayHello() =
    "Hello, World!"

printfn "%s" (sayHello())

// 4. Hello World with function parameters
let greet (name: string) =
    sprintf "Hello, %s!" name

printfn "%s" (greet "World")
printfn "%s" (greet "F#")

// 5. Hello World with multiple arities
let greetPerson() = "Hello, Stranger!"
let greetPerson(name: string) = sprintf "Hello, %s!" name
let greetPerson(firstName: string, lastName: string) =
    sprintf "Hello, %s %s!" firstName lastName

printfn "%s" (greetPerson())
printfn "%s" (greetPerson "Alice")
printfn "%s" (greetPerson("Jane", "Smith"))

// 6. Hello World with conditionals
let timeGreeting() =
    let hour = System.DateTime.Now.Hour
    if hour < 12 then
        "Good morning, World!"
    elif hour < 18 then
        "Good afternoon, World!"
    else
        "Good evening, World!"

printfn "%s" (timeGreeting())

// 7. Hello World multiple times
let repeatGreeting times =
    [1..times] |> List.iter (fun i -> printfn "Hello, World! %d" i)

repeatGreeting 5

// 8. Hello World with list
let greetings = ["Hello"; "Bonjour"; "Hola"; "Ciao"; "こんにちは"]

greetings |> List.iter (fun g -> printfn "%s, World!" g)

// 9. Hello World with map
let translateGreetings =
    Map [("en", "Hello"); ("es", "Hola"); ("fr", "Bonjour");
         ("de", "Hallo"); ("ja", "こんにちは")]

translateGreetings
|> Map.iter (fun lang greeting -> printfn "%s, World! (%s)" greeting lang)

// 10. Hello World with recursion
let rec greetCountdown n =
    if n > 0 then
        printfn "Hello, World! %d" n
        greetCountdown (n - 1)

greetCountdown 5

// Basic data types and operations

// Numbers (F# infers types)
let integer = 42          // int
let longInteger = 42L     // int64
let floatNumber = 3.14    // float
let doubleNumber = 3.14   // double
let decimalNumber = 3.14m // decimal

// Strings
let text = "Hello, F#!"
let textWithInterpolation = sprintf "The answer is %d" integer

// Characters
let char = 'A'

// Boolean
let boolTrue = true
let boolFalse = false

// Unit (like void)
let unitValue = ()

// Tuples
let tuple1 = (1, "hello")
let tuple2 = (1, "hello", 3.14)

// Lists (immutable linked lists)
let numbers = [1; 2; 3; 4; 5]
let stringList = ["apple"; "banana"; "cherry"]

// Arrays (mutable)
let array = [|1; 2; 3; 4; 5|]

// Maps (immutable dictionaries)
let map = Map [("name", "Alice"); ("age", 30); ("city", "NYC")]

// Sets (immutable)
let set = Set [1; 2; 3; 4; 5]

// Records (immutable)
type Person = { Name: string; Age: int; City: string }
let person = { Name = "Alice"; Age = 30; City = "NYC" }

// Discriminated unions
type Shape =
    | Circle of radius: float
    | Rectangle of width: float * height: float
    | Triangle of base: float * height: float

// Options (for handling nulls)
let someValue: int option = Some 42
let noValue: int option = None

// Data type examples
printfn "\n=== Data Types ==="
printfn "Integer: %d, Type: %A" integer (integer.GetType())
printfn "Float: %f, Type: %A" floatNumber (floatNumber.GetType())
printfn "String: %s, Type: %A" text (text.GetType())
printfn "Boolean: %b, Type: %A" boolTrue (boolTrue.GetType())
printfn "Tuple: %A" tuple1
printfn "List: %A" numbers
printfn "Map: %A" map
printfn "Record: %A" person

// Pattern matching examples
let describeValue x =
    match x with
    | 0 -> "Zero"
    | n when n < 0 -> sprintf "Negative: %d" n
    | n when n > 0 -> sprintf "Positive: %d" n

printfn "\n=== Pattern Matching ==="
printfn "Describe 5: %s" (describeValue 5)
printfn "Describe -3: %s" (describeValue -3)
printfn "Describe 0: %s" (describeValue 0)

// Pattern matching with shapes
let area shape =
    match shape with
    | Circle radius -> System.Math.PI * radius * radius
    | Rectangle (width, height) -> width * height
    | Triangle (base, height) -> 0.5 * base * height

let circle = Circle 5.0
let rectangle = Rectangle (4.0, 3.0)
let triangle = Triangle (6.0, 4.0)

printfn "\nShape areas:"
printfn "Circle radius 5: %f" (area circle)
printfn "Rectangle 4x3: %f" (area rectangle)
printfn "Triangle 6x4: %f" (area triangle)

// Functions and higher-order functions

// Basic functions
let add x y = x + y
let multiply x y = x * y

// Function composition
let add1 = (+) 1
let multiplyBy2 = (*) 2
let add1ThenMultiply = add1 >> multiplyBy2
let multiplyThenAdd1 = add1 << multiplyBy2

printfn "\n=== Function Composition ==="
printfn "Add 1 then multiply by 2: %d" (add1ThenMultiply 5)
printfn "Multiply by 2 then add 1: %d" (multiplyThenAdd1 5)

// Higher-order functions
let numbersList = [1; 2; 3; 4; 5]

let squares = List.map (fun x -> x * x) numbersList
let evenNumbers = List.filter (fun x -> x % 2 = 0) numbersList
let sum = List.reduce (+) numbersList

printfn "\n=== Higher-Order Functions ==="
printfn "Original: %A" numbersList
printfn "Squares: %A" squares
printfn "Even: %A" evenNumbers
printfn "Sum: %d" sum

// Pipeline operator
let result =
    numbersList
    |> List.map (fun x -> x * x)
    |> List.filter (fun x -> x > 5)
    |> List.sum

printfn "Pipeline result: %d" result

// List comprehensions
let moreSquares = [for x in 1..10 -> x * x]
let evenSquares = [for x in 1..10 do
                    let square = x * x
                    if square % 2 = 0 then yield square]

printfn "\n=== List Comprehensions ==="
printfn "More squares: %A" moreSquares
printfn "Even squares: %A" evenSquares

// Option handling
let safeDivide x y =
    if y = 0 then None
    else Some (x / y)

let divideAndPrint x y =
    match safeDivide x y with
    | Some result -> printfn "%d / %d = %d" x y result
    | None -> printfn "Cannot divide %d by zero" x

printfn "\n=== Option Handling ==="
divideAndPrint 10 2
divideAndPrint 10 0

// Working with records
type Employee = {
    Name: string
    Department: string
    Salary: float
    Skills: string list
}

let employees = [
    { Name = "Alice"; Department = "Engineering"; Salary = 80000.0; Skills = ["F#"; "C#"; "SQL"] }
    { Name = "Bob"; Department = "Marketing"; Salary = 65000.0; Skills = ["Marketing"; "Analytics"] }
    { Name = "Charlie"; Department = "Engineering"; Salary = 90000.0; Skills = ["Python"; "Java"; "F#"] }
]

let findEmployeesByDepartment dept =
    employees
    |> List.filter (fun emp -> emp.Department = dept)

let getAllSkills() =
    employees
    |> List.collect (fun emp -> emp.Skills)
    |> Set.ofList
    |> Set.toList

printfn "\n=== Record Operations ==="
printfn "Engineering employees: %A" (findEmployeesByDepartment "Engineering")
printfn "All skills: %A" (getAllSkills())

// Discriminated unions with pattern matching
type TrafficLight =
    | Red
    | Yellow
    | Green

let trafficAction light =
    match light with
    | Red -> "Stop"
    | Yellow -> "Prepare to stop"
    | Green -> "Go"

printfn "\n=== Discriminated Unions ==="
printfn "Red light action: %s" (trafficAction Red)
printfn "Green light action: %s" (trafficAction Green)

// Active patterns
let (|Even|Odd|) x =
    if x % 2 = 0 then Even else Odd

let describeNumber2 x =
    match x with
    | Even -> sprintf "%d is even" x
    | Odd -> sprintf "%d is odd" x

printfn "\n=== Active Patterns ==="
printfn "Describe 4: %s" (describeNumber2 4)
printfn "Describe 7: %s" (describeNumber2 7)

// Exception handling
let riskyOperation x =
    if x < 0 then
        failwith "Negative numbers not allowed"
    else
        sqrt (float x)

let safeOperation x =
    try
        let result = riskyOperation x
        Some result
    with
    | ex ->
        printfn "Error: %s" ex.Message
        None

printfn "\n=== Exception Handling ==="
printfn "Safe operation with 9: %A" (safeOperation 9)
printfn "Safe operation with -4: %A" (safeOperation -4)

// Computation expressions (async)
let downloadData url = async {
    printfn "Downloading from %s" url
    do! Async.Sleep 1000 // Simulate network delay
    return sprintf "Data from %s" url
}

let processData data = async {
    printfn "Processing: %s" data
    do! Async.Sleep 500
    return sprintf "Processed: %s" data
}

let downloadAndProcess url = async {
    let! data = downloadData url
    let! processed = processData data
    return processed
}

// Async execution example
printfn "\n=== Async Operations ==="
let asyncResult = downloadAndProcess "http://example.com/data"
printfn "Async result: %s" (Async.RunSynchronously asyncResult)

// Classes and objects
type Calculator() =
    member this.Add(x, y) = x + y
    member this.Subtract(x, y) = x - y
    member this.Multiply(x, y) = x * y

let calculator = Calculator()
printfn "\n=== Class Example ==="
printfn "Calculator Add: %d" (calculator.Add(5, 3))
printfn "Calculator Multiply: %d" (calculator.Multiply(4, 7))

// Interface implementation
type IShape =
    abstract member Area : float

type Square(side: float) =
    interface IShape with
        member this.Area = side * side

let square = Square(5.0)
printfn "Square area: %f" (square :> IShape).Area

// Mutable vs Immutable
// Immutable (preferred)
let mutableValue = 10
printfn "\n=== Mutability ==="
printfn "Original value: %d" mutableValue

// This requires the mutable keyword
let mutable mutableRef = 20
mutableRef <- 30
printfn "Changed value: %d" mutableRef

// Unit testing functions
let add a b = a + b
let multiply a b = a * b

let testAddition() =
    let result = add 2 3
    if result = 5 then
        printfn "✓ Addition test passed"
    else
        printfn "✗ Addition test failed: expected 5, got %d" result

let testMultiplication() =
    let result = multiply 4 5
    if result = 20 then
        printfn "✓ Multiplication test passed"
    else
        printfn "✗ Multiplication test failed: expected 20, got %d" result

printfn "\n=== Simple Tests ==="
testAddition()
testMultiplication()

// String operations
let stringOperations() =
    let text = "Hello, F# Programming!"

    printfn "Original: %s" text
    printfn "Upper case: %s" (text.ToUpper())
    printfn "Lower case: %s" (text.ToLower())
    printfn "Length: %d" (text.Length)
    printfn "Contains 'F#': %b" (text.Contains "F#")
    printfn "Split words: %A" (text.Split([|' '; ','; '!'|], System.StringSplitOptions.RemoveEmptyEntries))
    printfn "Replace 'F#' with 'Fsharp': %s" (text.Replace("F#", "Fsharp"))

stringOperations()

// Working with DateTime
let dateTimeOperations() =
    let now = System.DateTime.Now
    let tomorrow = now.AddDays 1.0
    let formatted = now.ToString("yyyy-MM-dd HH:mm:ss")

    printfn "\n=== DateTime Operations ==="
    printfn "Current time: %s" formatted
    printfn "Tomorrow: %s" (tomorrow.ToString("yyyy-MM-dd"))
    printfn "Day of week: %s" (now.DayOfWeek.ToString())

dateTimeOperations()

printfn "\n=== All F# Hello World Examples Complete! ==="

💻 F# Functional Programming Patterns fsharp

🟡 intermediate ⭐⭐⭐⭐

Advanced functional programming patterns, computation expressions, and type providers

⏱️ 35 min 🏷️ fsharp, functional programming, advanced, patterns, .net
Prerequisites: F# basics, Advanced functional programming concepts, .NET framework
// F# Functional Programming Patterns

// 1. Advanced Pattern Matching

// Pattern matching with nested data structures
type Tree<'T> =
    | Leaf of 'T
    | Node of Tree<'T> * Tree<'T>

let rec treeSum tree =
    match tree with
    | Leaf value -> value
    | Node (left, right) -> (treeSum left) + (treeSum right)

let myTree = Node (Node (Leaf 3, Leaf 7), Leaf 5)
printfn "Tree sum: %d" (treeSum myTree)

// Pattern matching with when guards
let classifyNumber x =
    match x with
    | x when x < 0 -> "Negative"
    | x when x = 0 -> "Zero"
    | x when x % 2 = 0 -> "Even positive"
    | _ -> "Odd positive"

printfn "Classify -5: %s" (classifyNumber -5)
printfn "Classify 4: %s" (classifyNumber 4)
printfn "Classify 7: %s" (classifyNumber 7)

// List patterns
let processList list =
    match list with
    | [] -> "Empty list"
    | [x] -> sprintf "Single element: %d" x
    | [x; y] -> sprintf "Two elements: %d, %d" x y
    | head :: tail -> sprintf "Head: %d, Tail: %A" head tail

printfn "Process []: %s" (processList [])
printfn "Process [42]: %s" (processList [42])
printfn "Process [1; 2; 3]: %s" (processList [1; 2; 3])

// 2. Active Patterns

// Single-case active pattern
let (|Even|Odd|) x = if x % 2 = 0 then Even else Odd

let describeNumberWithActivePattern x =
    match x with
    | Even when x > 0 -> sprintf "%d is positive even" x
    | Odd when x > 0 -> sprintf "%d is positive odd" x
    | Even -> sprintf "%d is zero or negative even" x
    | Odd -> sprintf "%d is negative odd" x

printfn "Active pattern describe 4: %s" (describeNumberWithActivePattern 4)

// Parameterized active pattern
let (|DivisibleBy|_|) divisor x =
    if x % divisor = 0 then Some (x / divisor) else None

let checkDivisibility x =
    match x with
    | DivisibleBy 3 quotient -> sprintf "%s is divisible by 3, quotient is %d" x quotient
    | DivisibleBy 5 quotient -> sprintf "%s is divisible by 5, quotient is %d" x quotient
    | _ -> sprintf "%s is not divisible by 3 or 5" x

printfn "Check 15: %s" (checkDivisibility 15)
printfn "Check 14: %s" (checkDivisibility 14)

// Partial active pattern
let (|FirstElement|_|) list =
    match list with
    | head :: _ -> Some head
    | [] -> None

let getFirstElementDescription list =
    match list with
    | FirstElement element -> sprintf "First element is %d" element
    | _ -> "List is empty"

printfn "First element [1;2;3]: %s" (getFirstElementDescription [1; 2; 3])
printfn "First element []: %s" (getFirstElementDescription [])

// 3. Higher-Order Functions and Function Composition

// Currying
let curry (f: 'a * 'b -> 'c) : 'a -> 'b -> 'c =
    fun x y -> f (x, y)

let uncurry (f: 'a -> 'b -> 'c) : 'a * 'b -> 'c =
    fun (x, y) -> f x y

// Usage
let addTuple (x, y) = x + y
let addCurried = curry addTuple
let addUncurried = uncurry add

printfn "Curried: %d" (addCurried 5 3)
printfn "Uncurried: %d" (addUncurried (5, 3))

// Function composition with types
let compose (g: 'b -> 'c) (f: 'a -> 'b) : 'a -> 'c =
    fun x -> g (f x)

// Forward composition operator (|)
let (|>) x f = f x
let (>>) g f = compose g f

// Pipeline with complex operations
let processNumber x =
    x
    |> float
    |> sqrt
    |> (*) 2.0
    |> int

printfn "Process number 16: %d" (processNumber 16)

// 4. Immutability and Persistent Data Structures

// Persistent stack implementation
type PersistentStack<'T>(private items: 'T list) =
    member this.IsEmpty = List.isEmpty items
    member this.Push item = PersistentStack (item :: items)
    member this.Pop() =
        match items with
        | [] -> None, this
        | head :: tail -> Some head, PersistentStack tail
    member this.Peek() = List.head items

// Usage
let stack = PersistentStack [3; 2; 1]
let Some(head, newStack) = stack.Pop()
printfn "Stack peek before: %d" stack.Peek
printfn "Stack pop: %d" head.Value
printfn "Stack peek after: %d" newStack.Peek

let finalStack = newStack.Push(4)
printfn "Final stack peek: %d" finalStack.Peek

// 5. Option and Result Types for Error Handling

// Result type (not built-in, so we create it)
type Result<'T, 'E> =
    | Success of 'T
    | Error of 'E

// Safe operations with Result type
let safeDivideResult x y =
    if y = 0 then
        Error "Division by zero"
    else
        Success (x / y)

// Result chaining
let bind (f: 'T -> Result<'U, 'E>) (result: Result<'T, 'E>) : Result<'U, 'E> =
    match result with
    | Success value -> f value
    | Error error -> Error error

let map (f: 'T -> 'U) (result: Result<'T, 'E>) : Result<'U, 'E> =
    match result with
    | Success value -> Success (f value)
    | Error error -> Error error

// Pipeline operator for Result type
let (|>>) result f = bind f

// Usage
let calculation =
    Success 20
    |>> safeDivideResult 2    // Success 10
    |>> safeDivideResult 5    // Success 2
    |>> safeDivideResult 0    // Error "Division by zero"

match calculation with
| Success result -> printfn "Calculation succeeded: %d" result
| Error error -> printfn "Calculation failed: %s" error

// 6. Computation Expressions (Workflow)

// Maybe computation expression
type MaybeBuilder() =
    member __.Return(x) = Some x
    member __.Bind(m, f) =
        match m with
        | Some value -> f value
        | None -> None
    member __.Zero() = None
    member __.Delay(f) = f()
    member __.Combine(a, b) =
        match a with
        | Some _ -> b
        | None -> None

let maybe = MaybeBuilder()

// Using maybe computation expression
let safeDivideMaybe x y =
    if y = 0 then None
    else Some (x / y)

let complexCalculation x =
    maybe {
        let! a = safeDivideMaybe x 2
        let! b = safeDivideMaybe a 3
        let! c = safeDivideMaybe b 4
        return c
    }

printfn "Maybe calculation 24: %A" (complexCalculation 24)
printfn "Maybe calculation 0: %A" (complexCalculation 0)

// 7. Async Computation Expressions

// Async workflow operations
let downloadDataAsync url = async {
    printfn "Downloading from %s" url
    do! Async.Sleep 1000 // Simulate network delay
    return sprintf "Data from %s" url
}

let processDataAsync data = async {
    printfn "Processing: %s" data
    do! Async.Sleep 500 // Simulate processing delay
    return sprintf "Processed: %s" data
}

let validateDataAsync processedData = async {
    printfn "Validating: %s" processedData
    do! Async.Sleep 200 // Simulate validation delay
    return processedData.Length > 10
}

let completeWorkflow url = async {
    try
        let! data = downloadDataAsync url
        let! processed = processDataAsync data
        let! isValid = validateDataAsync processed

        if isValid then
            return Success processed
        else
            return Error "Validation failed: data too short"
    with
    | ex -> return Error (sprintf "Workflow failed: %s" ex.Message)
}

// Async workflow execution
let workflowResult = completeWorkflow "http://example.com/data" |> Async.RunSynchronously
printfn "Workflow result: %A" workflowResult

// 8. List Processing with Pipelines

// Advanced list operations
let numbers = [1..100]

let processingPipeline =
    numbers
    |> List.filter (fun x -> x % 2 = 0)     // Filter evens
    |> List.map (fun x -> x * x)              // Square them
    |> List.filter (fun x -> x > 100)         // Filter > 100
    |> List.take 10                           // Take first 10
    |> List.sum                              // Sum them up

printfn "Processing pipeline result: %d" processingPipeline

// Fallback operator
let safeHead defaultValue list =
    list
    |> List.tryHead
    |> Option.defaultValue defaultValue

printfn "Safe head with non-empty: %d" (safeHead 0 [1; 2; 3])
printfn "Safe head with empty: %d" (safeHead 0 [])

// 9. Discriminated Unions for Domain Modeling

type PaymentMethod =
    | CreditCard of number: string * cvv: string * expiry: string
    | PayPal of email: string
    | BankTransfer of accountNumber: string * bankName: string

type PaymentStatus =
    | Pending
    | Completed
    | Failed of errorMessage: string

type PaymentResult = {
    Amount: decimal
    Method: PaymentMethod
    Status: PaymentStatus
    Timestamp: System.DateTime
}

let processPayment amount paymentMethod =
    let status =
        match paymentMethod with
        | CreditCard (number, cvv, expiry) ->
            if String.length number = 16 && String.length cvv = 3 then
                Completed
            else
                Failed "Invalid card details"
        | PayPal email ->
            if email.Contains "@" then
                Completed
            else
                Failed "Invalid email address"
        | BankTransfer (account, bank) ->
            if String.length account >= 8 then
                Completed
            else
                Failed "Invalid account number"

    {
        Amount = amount
        Method = paymentMethod
        Status = status
        Timestamp = System.DateTime.Now
    }

// Usage
let creditCardPayment = CreditCard ("1234567890123456", "123", "12/25")
let paymentResult = processPayment 50.0m creditCardPayment

printfn "Payment result: %A" paymentResult

// 10. Type Providers (mocked since they require external data)

// JSON Type Provider simulation
type JsonData = {
    Name: string
    Age: int
    City: string
}

let jsonExample = """
{
    "name": "Alice",
    "age": 30,
    "city": "New York"
}
"""

// In real F#, you would use FSharp.Data to create types from JSON
// let jsonProvider = JsonProvider<"""{ "name": string, "age": int }""">

// 11. Memoization and Caching

// Simple memoization
let memoize (f: 'a -> 'b) =
    let cache = System.Collections.Generic.Dictionary<'a, 'b>()
    fun x ->
        match cache.TryGetValue(x) with
        | true, cachedValue -> cachedValue
        | false, _ ->
            let result = f x
            cache.[x] <- result
            result

// Memoized Fibonacci
let rec fib n = if n < 2 then n else fib(n-1) + fib(n-2)

let memoizedFib = memoize fib

printfn "Memoized fib 30: %d" (memoizedFib 30)
printfn "Memoized fib 30 again: %d" (memoizedFib 30) // Cached

// 12. Lazy Evaluation

let expensiveOperation x =
    printfn "Computing expensive operation for %d" x
    System.Threading.Thread.Sleep(1000)
    x * x

let lazyValue = lazy (expensiveOperation 42)
printfn "Lazy value created (not computed yet)"
printfn "Lazy value: %d" lazyValue.Force()
printfn "Lazy value (cached): %d" lazyValue.Force()

// 13. Agent-based Programming (MailboxProcessor)

type Message =
    | Increment
    | Decrement
    | GetValue of replyChannel: AsyncReplyChannel<int>
    | Stop

let counterAgent = MailboxProcessor.Start(fun inbox ->
    let rec loop count =
        async {
            let! message = inbox.Receive()
            match message with
            | Increment -> return! loop (count + 1)
            | Decrement -> return! loop (count - 1)
            | GetValue replyChannel ->
                replyChannel.Reply count
                return! loop count
            | Stop -> ()
        }
    loop 0)

let agentExample = async {
    counterAgent.Post Increment
    counterAgent.Post Increment
    counterAgent.Post Increment
    counterAgent.Post Decrement

    let! value = counterAgent.PostAndReply GetValue
    printfn "Counter value: %d" value

    counterAgent.Post Stop
}

agentExample |> Async.RunSynchronously

// 14. Working with Units of Measure

[<Measure>] type m
[<Measure>] type s
[<Measure>] type kg

let distance = 5.0<m>
let time = 2.0<s>

// This would not compile: let invalid = distance + time
let speed = distance / time // Results in float<m/s>

printfn "Speed: %f m/s" speed

// 15. Quotations and Code Generation

open Microsoft.FSharp.Quotations

let simpleQuotation = <@ 1 + 2 @>
printfn "Quotation: %A" simpleQuotation

let functionQuotation = <@ fun x -> x * 2 @>
printfn "Function quotation: %A" functionQuotation

// Expression tree evaluation (simplified)
let eval (expr: Expr<int>) : int =
    match expr with
    | Patterns.Value(v, _) -> v
    | Patterns.Call(None, op, [Patterns.Value(a, _); Patterns.Value(b, _)]) ->
        match op with
        | Patterns.ValueWithReflection("op_Addition", _) -> a + b
        | Patterns.ValueWithReflection("op_Multiply", _) -> a * b
        | _ -> failwith "Unsupported operation"
    | _ -> failwith "Unsupported expression"

let additionQuotation = <@ 3 + 4 @>
printfn "Evaluated quotation: %d" (eval additionQuotation)

// 16. Reflection and Type Introspection

let examineType<'T>() =
    let t = typeof<'T>
    printfn "Type: %s" t.Name
    printfn "Namespace: %s" t.Namespace
    printfn "Is abstract: %b" t.IsAbstract
    printfn "Properties: %A" (t.GetProperties() |> Array.map (fun p -> p.Name))

examineType<System.String>()

printfn "\n=== All Functional Programming Patterns Complete! ==="

💻 F# .NET Interoperability fsharp

🟡 intermediate ⭐⭐⭐⭐

Seamless integration with C#, VB.NET, and .NET ecosystem including enterprise patterns

⏱️ 40 min 🏷️ fsharp, dotnet, interoperability, enterprise, backend
Prerequisites: F# basics, C# knowledge, .NET framework understanding, Enterprise patterns
// F# .NET Interoperability Examples

// 1. Basic .NET Interoperability

// Using .NET classes
open System
open System.Collections.Generic
open System.IO

// Working with DateTime
let getCurrentDateTime() =
    let now = DateTime.Now
    printfn "Current date and time: %s" (now.ToString("yyyy-MM-dd HH:mm:ss"))
    printfn "Day of week: %s" (now.DayOfWeek.ToString())
    printfn "Year: %d" now.Year

getCurrentDateTime()

// Working with .NET collections
let workWithCollections() =
    // List<T>
    let mutable stringList = List<string>()
    stringList.Add("Hello")
    stringList.Add("F#")
    stringList.Add("DotNet")

    printfn "List<T> contents:"
    for item in stringList do
        printfn "  %s" item

    // Dictionary<TKey, TValue>
    let dict = Dictionary<string, int>()
    dict.["one"] <- 1
    dict.["two"] <- 2
    dict.["three"] <- 3

    printfn "\nDictionary contents:"
    for kvp in dict do
        printfn "  %s = %d" kvp.Key kvp.Value

workWithCollections()

// 2. Interacting with C# classes and interfaces

// Define C#-style interface
type ILogger =
    abstract member Log: string -> unit
    abstract member LogError: string * exn -> unit

// C#-style class implementing interface
type ConsoleLogger() =
    interface ILogger with
        member _.Log(message) = printfn "INFO: %s" message
        member _.LogError(message, ex) =
            printfn "ERROR: %s - %s" message ex.Message

// Usage
let logger = ConsoleLogger()
logger.Log("Application started")
logger.LogError("Something went wrong", (ArgumentNullException("param")))

// 3. Extension Methods (as module functions)

module StringExtensions =
    let ToPascalCase (str: string) =
        if String.IsNullOrEmpty(str) then str
        else
            let words = str.Split([|' '; '-'; '_'|], StringSplitOptions.RemoveEmptyEntries)
            words
            |> Array.map (fun w ->
                if String.IsNullOrEmpty(w) then w
                else string w.[0].ToUpper() + w.Substring(1).ToLower())
            |> String.concat

// Usage
let testString = "hello_world_from_f#"
let pascalCase = StringExtensions.ToPascalCase testString
printfn "Pascal case of '%s': %s" testString pascalCase

// 4. C# Property Patterns in F#

type Person(name: string, age: int) =
    member _.Name = name
    member _.Age = age
    member _.IsAdult = age >= 18
    member _.Description = sprintf "%s is %d years old" name age

// Create instance
let person = Person("Alice", 30)
printfn "Person: %s" person.Description
printfn "Is adult: %b" person.IsAdult

// 5. Implementing IDisposable pattern

type DatabaseConnection(connectionString: string) =
    let mutable isConnected = false

    member _.Connect() =
        if not isConnected then
            printfn "Connecting to database: %s" connectionString
            isConnected <- true
        else
            printfn "Already connected to database"

    member _.Disconnect() =
        if isConnected then
            printfn "Disconnecting from database"
            isConnected <- false
        else
            printfn "Already disconnected"

    interface IDisposable with
        member _.Dispose() = _.Disconnect()

// Usage with using block
let useDatabase() =
    use connection = DatabaseConnection("Server=localhost;Database=Test;")
    connection.Connect()
    printfn "Working with database connection..."
    // Connection is automatically disposed when using block ends

useDatabase()

// 6. Working with .NET Events

type EventBus() =
    let event = new Event<EventHandler<EventArgs>>()

    [<CLIEvent>]
    member _.OnMessage = event.Publish

    member _.TriggerMessage(message: string) =
        let args = EventArgs()
        printfn "Triggering event with message: %s" message
        event.Trigger(this, args)

let eventBus = EventBus()

// Subscribe to event (C#-style)
let eventHandler (sender: obj) (e: EventArgs) =
    printfn "Event received from %A at %s" sender (DateTime.Now.ToString())

// Add event listener
eventBus.OnMessage.AddHandler(EventHandler<EventArgs>(eventHandler))

// Trigger event
eventBus.TriggerMessage("Hello from F#!")

// 7. LINQ Integration

// Using LINQ with F#
open System.Linq

let useLinq() =
    let numbers = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]

    // Convert to .NET IEnumerable and use LINQ
    let enumerable = numbers :> IEnumerable<int>

    // LINQ operations
    let evenNumbers = enumerable.Where(fun x -> x % 2 = 0)
    let sortedNumbers = numbers.OrderByDescending(fun x -> x)
    let groupedNumbers = numbers.GroupBy(fun x -> x % 3)

    printfn "Even numbers (LINQ): %A" (Seq.toList evenNumbers)
    printfn "Sorted descending (LINQ): %A" (Seq.toList sortedNumbers)

    printfn "Grouped by mod 3:"
    for group in groupedNumbers do
        printfn "  Mod %d: %A" group.Key (Seq.toList group)

useLinq()

// 8. Async/Await Integration with C# patterns

type HttpClient() =
    member _.GetAsync(url: string) = async {
        printfn "Making GET request to %s" url
        do! Async.Sleep 1000 // Simulate network delay
        return sprintf "Response from %s" url
    }

    member _.PostAsync(url: string, data: string) = async {
        printfn "Making POST request to %s with data: %s" url data
        do! Async.Sleep 1500 // Simulate network delay
        return sprintf "Posted data to %s" url
    }

let httpClient = HttpClient()

// Async workflow similar to C# async/await
let makeApiCalls() = async {
    try
        let! response1 = httpClient.GetAsync("https://api.example.com/users")
        printfn "GET response: %s" response1

        let! response2 = httpClient.PostAsync("https://api.example.com/data", "{'key': 'value'}")
        printfn "POST response: %s" response2

        return ["GET result: " + response1; "POST result: " + response2]
    with
    | ex ->
        printfn "API call failed: %s" ex.Message
        return ["Error: " + ex.Message]
    }

// Execute async workflow
let apiResults = makeApiCalls() |> Async.RunSynchronously
printfn "API results: %A" apiResults

// 9. Interoperability with C# Null Handling

let handleNullable() =
    // Working with nullable types
    let nullableInt: Nullable<int> = Nullable(42)
    let nullableIntNull = Nullable()

    printfn "Nullable int: %d" nullableInt.Value
    printfn "Nullable int.HasValue: %b" nullableInt.HasValue
    printfn "Nullable int null.HasValue: %b" nullableIntNull.HasValue

    // Convert to F# Option
    let nullableToOption (nullable: Nullable<'T>) =
        if nullable.HasValue then Some nullable.Value else None

    let optionFromNull = nullableToOption nullableIntNull
    printfn "Option from null nullable: %A" optionFromNull

handleNullable()

// 10. C# Attributes in F#

// Using .NET attributes
[<Serializable>]
type UserData =
    {
        [<System.ComponentModel.DisplayName("User ID")>]
        Id: int

        [<System.ComponentModel.Description("The user's name")>]
        Name: string

        [<System.ComponentModel.DefaultValue("")>]
        Email: string
    }

// Reflection on attributes
let inspectAttributes() =
    let userType = typeof<UserData>
    let properties = userType.GetProperties()

    printfn "UserData properties with attributes:"
    for prop in properties do
        let displayName =
            prop.GetCustomAttributes(typeof<System.ComponentModel.DisplayNameAttribute>, false)
            |> Seq.tryHead
            |> Option.map (fun attr -> attr.DisplayName)
            |> Option.defaultValue prop.Name

        let description =
            prop.GetCustomAttributes(typeof<System.ComponentModel.DescriptionAttribute>, false)
            |> Seq.tryHead
            |> Option.map (fun attr -> attr.Description)
            |> Option.defaultValue ""

        printfn "  %s (%s): %s" displayName prop.PropertyType.Name description

inspectAttributes()

// 11. Task Parallel Library Integration

let useParallelLibrary() =
    let numbers = [1..20]

    // Parallel.For (imperative)
    Array.Parallel.For(numbers |> Array.ofList, fun x ->
        let result = x * x
        printfn "Processing %d -> %d" x result
    ) |> ignore

    // Parallel.ForEach
    let words = ["hello"; "world"; "fsharp"; "parallel"]
    Parallel.ForEach(words, fun word ->
        printfn "Processing word: %s (length: %d)" word word.Length
    ) |> ignore

    // PLINQ
    let parallelResult =
        numbers
        |> AsParallel()
        |> Where(fun x -> x % 2 = 0)
        |> Select(fun x -> x * x)
        |> ToArray()

    printfn "PLINQ even squares: %A" parallelResult

useParallelLibrary()

// 12. Configuration and AppSettings

type AppConfiguration() =
    member val ConnectionString = "Server=localhost;Database=MyApp;" with get, set
    member val LogLevel = "Info" with get, set
    member val MaxRetries = 3 with get, set
    member val ApiKey = "default-key" with get, set

    member _.LoadFromFile(filePath: string) =
        if File.Exists(filePath) then
            let lines = File.ReadAllLines(filePath)
            for line in lines do
                let parts = line.Split('=')
                if parts.Length = 2 then
                    match parts.[0].Trim() with
                    | "ConnectionString" -> _.ConnectionString <- parts.[1].Trim()
                    | "LogLevel" -> _.LogLevel <- parts.[1].Trim()
                    | "MaxRetries" -> _.MaxRetries <- int parts.[1].Trim()
                    | "ApiKey" -> _.ApiKey <- parts.[1].Trim()
                    | _ -> ()
        else
            printfn "Config file not found: %s" filePath

// Usage
let config = AppConfiguration()
printfn "Default config: ConnectionString=%s, LogLevel=%s" config.ConnectionString config.LogLevel

// 13. Dependency Injection Patterns

type ILogger2 =
    abstract member LogInfo: string -> unit
    abstract member LogWarning: string -> unit
    abstract member LogError: string -> unit

type FileLogger(filePath: string) =
    interface ILogger2 with
        member _.LogInfo(message) =
            File.AppendAllText(filePath, sprintf "[INFO] %s: %s%s"
                (DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) message Environment.NewLine)
        member _.LogWarning(message) =
            File.AppendAllText(filePath, sprintf "[WARN] %s: %s%s"
                (DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) message Environment.NewLine)
        member _.LogError(message) =
            File.AppendAllText(filePath, sprintf "[ERROR] %s: %s%s"
                (DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) message Environment.NewLine)

type UserService(logger: ILogger2) =
    member _.CreateUser(name: string, email: string) =
        logger.LogInfo(sprintf "Creating user with name: %s, email: %s" name email)
        // User creation logic here
        { Name = name; Email = email; CreatedAt = DateTime.Now }

type UserRepository =
    member _.Save(user) =
        // Database save logic here
        printfn "Saving user: %A" user

type Application(logger: ILogger2) =
    let userService = UserService(logger)
    let userRepository = UserRepository()

    member _.RegisterUser(name: string, email: string) =
        logger.LogInfo("Starting user registration")
        let user = userService.CreateUser(name, email)
        userRepository.Save(user)
        logger.LogInfo(sprintf "User registered successfully: %s" name)

// Dependency injection usage
let fileLogger = FileLogger("app.log")
let application = Application(fileLogger)
application.RegisterUser "John Doe" "[email protected]"

// 14. Interop with C# async patterns (Task-based)

type CSharpStyleService() =
    // Method returning Task<T> like in C#
    member _.GetDataAsync() : System.Threading.Tasks.Task<string> =
        System.Threading.Tasks.Task.Run(fun () ->
            System.Threading.Thread.Sleep(1000)
            "Data from C#-style service"
        )

    member _.ProcessDataAsync(data: string) : System.Threading.Tasks.Task<bool> =
        System.Threading.Tasks.Task.Run(fun () ->
            System.Threading.Thread.Sleep(500)
            not (String.IsNullOrEmpty(data))
        )

// Convert C# Task to F# Async
let taskToAsync (task: System.Threading.Tasks.Task<'T>) : Async<'T> =
    Async.FromContinuations((fun (success, error, canceled) ->
        task.ContinueWith(fun (t: System.Threading.Tasks.Task<'T>) ->
            if t.IsFaulted then
                error (t.Exception)
            elif t.IsCanceled then
                canceled ()
            else
                success t.Result)))

let callCSharpService() = async {
    let service = CSharpStyleService()

    // Convert Task to Async
    let! data = service.GetDataAsync() |> taskToAsync

    let! isValid = service.ProcessDataAsync(data) |> taskToAsync

    if isValid then
        return sprintf "Valid data from C# service: %s" data
    else
        return "Invalid data from C# service"
}

let csharpResult = callCSharpService() |> Async.RunSynchronously
printfn "C# service result: %s" csharpResult

// 15. JSON Serialization with Newtonsoft.Json (like C#)

type Product = {
    Id: int
    Name: string
    Price: decimal
    InStock: bool
}

let serializeToJson() =
    open Newtonsoft.Json

    let product = { Id = 1; Name = "Laptop"; Price = 999.99m; InStock = true }

    // Serialize to JSON
    let json = JsonConvert.SerializeObject(product, Formatting.Indented)
    printfn "Serialized JSON:\n%s" json

    // Deserialize from JSON
    let deserializedProduct = JsonConvert.DeserializeObject<Product>(json)
    printfn "Deserialized product: %A" deserializedProduct

serializeToJson()

// 16. Database Operations with Entity Framework patterns

// Mock Entity Framework-like operations
type DbContext(connectionString: string) =
    member _.SaveChanges() =
        printfn "Saving changes to database with connection: %s" connectionString
        1 // Return number of affected rows

type UserRepository2(db: DbContext) =
    member _.Add(user: UserData) =
        printfn "Adding user to database: %A" user
        user

    member _.Update(user: UserData) =
        printfn "Updating user in database: %A" user
        user

    member _.Delete(id: int) =
        printfn "Deleting user with ID: %d" id

    member _.FindById(id: int) =
        // Simulate database lookup
        if id > 0 then
            Some { Id = id; Name = sprintf "User %d" id; Email = sprintf "user%[email protected]" id }
        else
            None

// Repository pattern usage
let dbContext = DbContext("Server=localhost;Database=Test;")
let userRepository2 = UserRepository2(dbContext)

let performDatabaseOperations() =
    // Create
    let newUser = userRepository2.Add({ Id = 0; Name = "New User"; Email = "[email protected]" })

    // Update
    let updatedUser = { newUser with Name = "Updated User" }
    userRepository2.Update(updatedUser) |> ignore

    // Read
    match userRepository2.FindById(1) with
    | Some user -> printfn "Found user: %A" user
    | None -> printfn "User not found"

    // Save changes
    let rowsAffected = dbContext.SaveChanges()
    printfn "Rows affected: %d" rowsAffected

performDatabaseOperations()

printfn "\n=== All F# .NET Interoperability Examples Complete! ==="