
You'll trace where F# came from: Don Syme's work at Microsoft Research in the early 2000s, its OCaml and ML lineage, and the languages that shaped its design. You'll follow the milestones from F# 1.0 in 2005 to today and see how academic ideas became the first functional-first language to ship as a first-class citizen of a major industrial platform.
You'll write your first F# program that greets a character and prints a few values using printfn and its typed format specifiers (%s, %d, %f, %A). You'll see how F# enforces type-safe formatting at compile time, watch a wrong specifier turn into a build failure, and assemble a complete status report that mixes strings, numbers, and a collection.
You'll declare values with let, discover why bindings are immutable by default, and watch the compiler reject a reassignment. Then you'll convert a binding into a mutable one with the <- operator and see the difference firsthand, so immutability lands through doing rather than reading.
You'll bind a value of each core primitive type — int, float, bool, string, and char — and print both the value and its inferred type with printfn "%A". You'll see how F# infers types automatically while still supporting explicit annotations like let manaPool : int = 100, and how literal suffixes steer inference as you add your own bindings.
You'll combine primitive values with arithmetic (+, -, *, /, %), comparison (=, <>, <, >), and logical (&&, ||, not) operators, and see why integer and float division behave differently. You'll write an expression that returns true only when a value falls inside a given range, reinforcing operator precedence and the boolean type.
You'll build messages with the modern $"..." interpolated string syntax and reach for string operations like String.length, ToUpper, and Substring. You'll run calculations inside the braces and slice a string apart, then compare interpolation against the older sprintf form so you recognize both styles in real F# codebases.
You'll step back from typing code to build a mental model of F#'s Hindley-Milner-style type inference, following how the compiler propagates type information from literals outward through expressions. You'll compare it with C#'s var, learn where inference stops, and understand why F# so rarely needs explicit annotations — a model that makes the function lectures ahead far clearer.
You'll learn what "functional-first" really means and why it matters: immutability by default, expression-oriented code, type inference everywhere, and pragmatic interop with object-oriented .NET libraries. You'll see how F# differs from purely functional Haskell, where it sits on the paradigm map, and understand the deliberate tradeoffs it makes in favor of succinctness, correctness, and refactor safety.
You'll discover that if in F# is an expression that returns a value, not a statement, by binding the result of an if directly to a name and printing it. You'll compare it with a C-style ternary, see why both branches must return the same type, then make a multi-way decision from a number using a single if/elif/else expression.
You'll write your first match expressions on simple values, using wildcard and literal patterns and paying attention to the compiler's exhaustiveness warnings. You'll classify a number as "zero", "positive", or "negative", then build a lookup table that matches specific values and let the compiler flag any case you miss.
You'll add conditional guards to match using the when keyword, so your patterns react to runtime conditions and not just shape. You'll distinguish "small", "medium", and "large" ranges, then combine tuples with computed guards to build richer logic — seeing how match goes far beyond a switch statement.
You'll work with F#'s imperative loops: for i in 1..n do, for x in xs do, and while condition do. You'll print a small table with a for loop and walk a collection item by item, then write a while loop that runs until a counter crosses a threshold, getting an explicit handle on the imperative side of F# before later lectures replace it with higher-order functions.
You'll use ranges like 1..n and stepped ranges like 10..2..20, then build sequence expressions with seq { ... } that yield values on demand. You'll generate a sequence of squares, see why sequences are lazy by design, then write a sequence expression that yields only the multiples of three below a limit, blending iteration and condition into one declarative shape.
You'll map out the world F# lives in: the .NET runtime, the BCL, NuGet, MSBuild, and the tooling layer (dotnet CLI, Ionide, Rider, Visual Studio), and where F# sits among the other CLR languages. You'll see how F# shares libraries and deployment targets with C# while bringing its own F#-specific toolkit and unique outputs like .fsx scripting — a clear picture of what "writing F#" actually means today.
You'll define your first F# function with let, call it, and print the result, learning that functions are values, parameters are space-separated rather than comma-separated, and no return keyword is needed. You'll then write functions with multiple steps, see that functions are first-class values, and chain two of them together — planting the most fundamental building block of functional F#.
You'll add explicit type annotations to function parameters and return types, and watch the compile error you get when an annotation conflicts with the body. You'll annotate functions that work with ints, strings, floats, and booleans, and see how annotations document intent without changing behavior.
You'll discover that multi-parameter F# functions are curried under the hood, so supplying fewer arguments hands you back a new function. You'll partially apply a two-argument function to lock in one value, build a small family of helpers from a single definition, then chain partial applications across a three-stage function — locking in one of F#'s most useful idioms.
You'll meet the fun x -> ... lambda syntax and pass a lambda into a higher-order function like List.map to transform a list of numbers. You'll write inline lambdas with no name, reach for List.filter to keep only the elements you want, then chain map and filter together — getting your first hands-on experience of functions as first-class values.
You'll thread a value through a chain of transformations with the pipeline operator |> and build new functions from existing ones with the composition operator >>. You'll pipe a list through filter and map, compose two small functions with >>, then combine pipe and compose to square a list of values — two of the most visually distinctive features of idiomatic F#.
You'll write a recursive function with let rec using the classic factorial example and learn why F# requires the explicit rec marker. You'll start with a simple countdown, compute a factorial, then write recursive functions that accumulate a running total down to a base case — your first taste of recursion before later lectures revisit it with pattern matching and tail calls.
You'll get an honest appraisal of F#'s tradeoffs: a smaller community than C# or Python, fewer beginner resources, an OO-shaped standard library that sometimes fights the functional grain, and gaps in parts of the ecosystem. You'll weigh that against its real strengths — domain modeling, finance, data pipelines, and concurrent backends — so you know when F# is the right call and when another language fits better.
You'll work with F#'s immutable singly-linked lists using [1; 2; 3] syntax and the cons operator ::, prepending an element and printing the result. You'll contrast lists with arrays to know when each is preferred, peek at a list's head and tail, then prepend a new element onto an existing list and print it with %A — anchoring the most idiomatic collection in F#.
You'll create arrays with [|1; 2; 3|], index into them with .[i], and mutate elements in place, seeing arrays as the mutable, performance-oriented collection. You'll then create an array of zeros with Array.zeroCreate and fill it with the squares of the indices using a for loop, getting a feel for when arrays beat lists.
You'll build tuples like (1, "Anna", true), destructure them with let (a, b, c) = ..., and return a tuple from a function to express multiple results without a class. You'll print the quotient and remainder returned from a division function, see why position matters, then write a function that returns the min and max of a pair as a tuple and destructure the result.
You'll declare a record type with named fields, create an instance with the { Field = value; ... } syntax, and use the {record with Field = value} copy-and-update syntax that preserves immutability. You'll read fields with dot notation, watch the compiler refuse a direct mutation, then produce a new copy with updated fields — learning the data-modeling style that defines real-world F# code.
You'll model "one of several possible shapes" with discriminated unions, building a Shape DU whose Circle, Rectangle, and Triangle cases each carry their own data, then matching to compute an area. You'll add a Square case and extend the match, watching the compiler's exhaustiveness warning fire if you forget — a hallmark feature that sets F# apart.
You'll build immutable maps and sets with Map.ofList and Set.ofList, then look up values with Map.find, add entries that return a new map, and check membership. You'll construct a small map of names to values and look two up, add to a set to get a new set, then combine a map and a set in one example — rounding out the collection vocabulary you'll use everywhere downstream.
You'll examine the technical specs of modern F#: compilation to IL, JIT and AOT options, GC behavior, startup costs, memory footprint, and benchmark positioning against C# on web and numeric workloads. You'll see how value-type records, struct unions, inline functions, and Span support let F# compete with C# performance while keeping its functional style — proof that "functional" does not mean "slow."
You'll write your first async workflow with the async { ... } computation expression, sleeping with Async.Sleep and then printing a message, and start it with Async.RunSynchronously. You'll see the difference between defining an async (just a description) and running it (actually doing the work), return a value from an async, then run workflows in sequence so the asynchronous behavior shows up in the console.
You'll compose multiple async workflows into one parallel operation with Async.Parallel and measure the wall-clock difference against sequential execution using a Stopwatch. You'll run several one-second workflows the slow way and then all at once, print the total elapsed time, then combine parallel workflows that compute results into an array — seeing how parallelism cuts total time on independent work.
You'll use the task { ... } computation expression to produce .NET Task values that interoperate directly with C# libraries, calling a Task-returning method and awaiting its result with let!. You'll see why a task starts hot, pull a Task into the async world, and await both an async and a task in the same workflow, so you can use any .NET library regardless of its asynchrony style.
You'll defer computation with lazy bindings that compute their value only on demand, and contrast eager List operations with lazy Seq pipelines. You'll watch a lazy expression run only when forced and see that Seq.map does no work until iterated, then build an infinite Fibonacci stream with Seq.unfold that yields values without precomputing them and force evaluation only at the end.
You'll use MailboxProcessor, F#'s lightweight, thread-safe message-processing primitive, to encapsulate state and handle concurrency without locks. You'll design a message vocabulary, build a counter agent that responds to Increment and GetValue messages, then build a second agent that tracks experience and replies on demand — discovering the actor pattern F# offers out of the box.
You'll see who actually runs F# in production: companies running it on real commerce and financial platforms, GitHub language stats over the past decade, and the steady NuGet trends behind the most-downloaded F# libraries. You'll get a sense of the community across the F# Software Foundation, the dotnet/fsharp repo, and where developers actually gather — grounding the course in evidence that this is a real, working language.
You'll write generic code, starting with let identity x = x and watching the compiler infer a polymorphic type, then adding explicit type parameters with let swap (a:'a) (b:'b) = (b, a). You'll call these functions with different types and print the results, work with three type parameters at once, then write a constrained generic function that returns the larger of two comparable values — learning the 'a syntax that pervades real codebases.
You'll replace exception-based error handling with Result<'T, 'TError> and Option<'T>, modeling success and failure as data. You'll write a function that returns an Option and unwrap it with pattern matching, write a safeDivide that returns a Result and match on its Ok and Error cases, then chain results together with Result.bind — your canonical entry point to railway-oriented programming.
You'll chain fallible operations cleanly with a Result-aware computation expression, building a minimal result { ... } builder and using let! and return! to short-circuit on the first error. You'll run a sequence of steps that short-circuit, learn the difference between let and let!, then watch two paths flow through one pipeline — meeting one of F#'s most powerful abstractions over control flow.
You'll combine List.map, List.filter, List.reduce, and List.fold into pipelined expressions that replace explicit loops. You'll power up every element, keep only the values you want, crush a list into a single value, and compare reduce with fold, then build a single pipeline that computes the sum of squares of the even numbers from 1 to 20 — cementing the declarative style.
You'll use type providers such as JsonProvider and CsvProvider from FSharp.Data, which generate types from a sample at compile time and give you full IntelliSense over external data with no boilerplate. You'll read a tiny JSON sample and access a typed field, decode a nested reward tree, then pull rows from a CSV sample — showcasing a feature unique to F# in the .NET world.
You'll define active patterns with the (|...|) syntax to match on derived properties of values, not just their literal shape. You'll build an (|Even|Odd|) pattern and use it inside a match to classify numbers, classify across several cases at once, then define partial active patterns like (|Positive|_|) and (|Critical|_|) and use them alongside ordinary patterns — one of F#'s most loved expressive features.
You'll visualize every stage an F# file passes through: parsing and type-checking by FSharp.Compiler.Service, elaboration into a typed AST, lowering to .NET IL in a managed assembly, JIT compilation at runtime, and optional AOT. You'll see what artefacts the compiler emits at each step and where they live on disk, so you can reason about deployment, performance, and tooling with confidence.
You'll explore conceptually how F#'s type inference walks expressions, generates type variables, unifies constraints, and generalizes to polymorphic types. Through inference-flow diagrams you'll cover the value restriction, statically resolved type parameters, and how F# inference compares with C#'s var — and learn to predict the inferred type of any expression and read what an inference error is really telling you.
You'll follow a visual walkthrough of how F#'s lists, maps, and sets stay immutable without copying entire structures, using structural sharing and persistent trees. You'll contrast this with naive deep-copy approaches and understand the performance implications, leaving convinced that immutability in F# is not a tax but a carefully engineered representation that delivers safety and reasonable performance at once.
You'll learn two of the F# community's most discussed patterns conceptually: railway-oriented programming for error handling with Result chains, and smart constructors using single-case discriminated unions and private constructors to make illegal states unrepresentable. Through diagrams and decision flows you'll build a vocabulary you can spot in any F# codebase, whatever the business domain.
You'll see how records (product types) and discriminated unions (sum types) compose into algebraic data types that model real business domains precisely. Working through a diagram of the states and transitions of an order's lifecycle, you'll experience Scott Wlaschin's "make illegal states unrepresentable" philosophy and feel why domain-driven design comes naturally in F#.
You'll survey the areas where F# punches above its weight: quantitative finance and risk modeling, ETL and data pipelines over .NET data sources, internal DSLs, compiler and analyzer construction, and even web frontends. Through case-study-style visuals of typical project layouts, you'll learn to recognize the problems where reaching for F# at work tomorrow would be a serious productivity win.
This course contains the use of artificial intelligence.
F# is the quietly powerful language behind some of the most reliable systems in finance, data engineering, and compiler tooling. While the rest of the world argues about JavaScript frameworks, F# developers are shipping concise, correct code on top of the entire .NET ecosystem — code that catches whole categories of bugs at compile time and reads like the specification it implements. If you have ever felt that your codebase is fighting you with null checks, defensive copies, and runtime surprises, F# offers a different bargain: immutability by default, exhaustive pattern matching, and a type system that genuinely helps you think. This course is your structured path into that world, from the very first printfn to building real domain models with algebraic data types.
The course is built across six sections, woven so that concepts and code reinforce each other. Each coding section opens with a short conceptual lecture — the history, the design philosophy, the ecosystem, the "why" — and then drops you straight into hands-on coding: printing to the console, let bindings, primitive types, operators, control flow, functions, currying, pipelines, recursion, and the collections that define idiomatic F# (lists, arrays, tuples, records, discriminated unions, maps, and sets). The advanced sections follow the same rhythm, pairing context with practice across async workflows, Async.Parallel, Task interop with C#, lazy evaluation, MailboxProcessor actors, generics, Result and Option, computation expressions, type providers, and active patterns. The course then closes with a deeper run of conceptual lectures — the compilation pipeline from .fs to IL to machine code, the type-system internals and generalization, persistent data structures and structural sharing, railway-oriented programming and smart constructors, domain modeling with algebraic data types, and where F# lives in production — so you walk away understanding not just how F# works but why it was built that way.
This course is for developers who want to write safer, clearer code — whether you are a C# engineer curious about the functional side of .NET, a Python or JavaScript developer looking for stronger guarantees, or a programmer entirely new to functional-first thinking. You should be comfortable with basic programming concepts like variables, functions, and loops in some language; no .NET or functional experience is required. By the end you will be able to read and write idiomatic F#, model domains with discriminated unions, handle errors without exceptions, and structure concurrent code with confidence.
What sets this course apart is the balance between deep conceptual explanations of why F# works the way it does and concrete, hands-on coding through every feature of the language. You will not just memorize syntax — you will understand the design philosophy behind functional-first programming and the runtime characteristics that make F# a serious production choice. Enroll now and start writing the kind of code that you actually want to maintain six months from now.