A jonnify course
F#
In Depth
The ML-family language on .NET — typed, functional, pragmatic — taught from first principles.
Six chapters: where F# comes from, the language in depth, bridges for C# and Elixir developers, algorithms & data structures, and a real DevOps tool built end to end. C1–C3 run nine modules of three dives each; C4 re-derives the Elixir course’s twelve-module algorithms arc in F#; C5 ships a working F# tool. The code is idiomatic and runnable; the diagrams compute the real thing.
How to read this
F# is a functional-first language in the ML family, running on the same .NET runtime as C#. This course takes it seriously — not as a curiosity beside C#, but as a complete way to build software: types that make illegal states unrepresentable, immutability by default, and composition as the primary verb.
The shape is deliberate. History shows where the ideas come from; the language chapter teaches F# in depth on its own terms; the C# and Elixir bridges translate the habits you already have from each community; algorithms put the language under load — the same twelve-module arc the Elixir course runs, re-derived in F#; and pragmatic programming ships a real DevOps tool. Each chapter reuses the one before it.
Pick a chapter from the arc below to see what it covers and what it stands on. The full module directory follows.
The arc · select a chapter
Where F# comes from — the ML lineage and the .NET runtime.
The course is one curve, not six disconnected topics. Read it in order and each chapter is a consequence of the last.
One idea, early: composition
The thread that runs through every chapter is composition. F# gives it two operators you will reach for
constantly: the pipe |>, which feeds a value left-to-right into the next function,
and forward composition >>, which glues two functions into one. Both read in the
order the work happens.
Three pure functions are wired below: double maps x to 2x, increment adds one, and square maps x to x². Set the input, toggle which functions take part, and watch the F# pipeline and its result rebuild.
The pipe · build a pipeline
3 |> double // => 6 |> increment // => 7 |> square // => 49
A pipeline reads left to right: x |> f |> g is
g(f(x)). Turn every function off and the pipeline is the identity — it returns its
input untouched. C1.04 makes |>, >>, and their laws precise.
The map
The full course, chapter by chapter. Every module here is specified and on the way; as each ships it becomes a live link. The final module of each chapter is a hands-on, richly visual lab.
History
Open chapter →Where F# comes from — the ML lineage and the .NET runtime. Two modules, three dives each.
The ML lineage & typed functional programming
λ-calculus → LISP → ML → the typed, inferred branch that becomes F#.
- C0.1.1From λ-calculus to LISP
- C0.1.2The ML family — SML, OCaml & Hindley–Milner inference
- C0.1.3F#’s birth — Don Syme, MSR & OCaml-on-.NET
The .NET runtime & the open-source turn
Managed execution on the CLR, interop, and F# going open and cross-platform.
- C0.2.1The CLR — managed execution, the type system & interop
- C0.2.2.NET Framework → .NET Core → unified .NET
- C0.2.3The F# Software Foundation & the community
Values, types & FSI
The data you build with; F# Interactive as a tool.
let bindings, immutability & shadowing
A name binds a value; rebinding shadows, it does not mutate.
Functions, currying & partial application
Every function takes one argument; the rest is currying.
The pipe |> and composition >>
Threading values and gluing functions, left to right.
Pattern matching & active patterns
Branch by structure; extend matching with your own patterns.
Discriminated unions & records
Sum and product types; making illegal states unrepresentable.
Collections — list, array, seq, Map & Set
The core containers and when to reach for each.
Option, Result & railway-oriented errors
No nulls, no exceptions for control flow — errors in the type.
Computation expressions & async
A lab: build a small computation expression and run async work.
F# for C# developers
Open chapter →Translate every C# habit into its idiomatic F# form. Nine modules, three dives each.
From classes to modules & functions
Where behaviour lives when there is no class to hang it on.
From mutable state to immutability & expressions
Everything is an expression; values do not change.
From null to Option, from exceptions to Result
Absence and failure become ordinary, type-checked values.
From inheritance to discriminated unions
Model variation with data + pattern matching, not hierarchies.
From loops to recursion, map & fold
Iterating without mutating an index.
From interfaces to function types & object expressions
A function is the smallest interface; object expressions fill the gaps.
From LINQ to seq pipelines
The query you know, as a lazy F# sequence pipeline.
Interop — calling C# from F# and back
One solution, two languages, clean boundaries.
Mixing paradigms in one solution
A lab: an F# core behind a C# host, end to end.
F# for Elixir developers
Open chapter →The developer’s journey to F#, coming from Elixir — the Elixir-community parallel to C2. Nine modules, three dives each.
Two functional runtimes — the BEAM & the CLR
What carries over from the BEAM, and what the managed runtime changes.
From dynamic to static types
Type inference, and making illegal states unrepresentable.
Pattern matching, sharpened
Familiar ground, plus exhaustiveness and active patterns.
The pipe you already know (+ composition)
The same |>, plus forward composition >>.
Tuples & atoms → records & unions
Typed product and sum types for tuples and atoms.
{:ok, _} / {:error, _} → Result & Option
The tagged tuples you return, as types.
Processes & GenServer → MailboxProcessor
F#’s actor, async workflows, and what OTP adds.
Protocols & behaviours → interfaces
Interfaces and object expressions for protocols.
Mix & OTP → dotnet & .NET
A lab: the dotnet CLI, project structure, a first app.
Algorithms & Data Structures
The Elixir course’s E4 arc, re-derived in F# — from lists to branded CHAMP tries — each cross-linked to its E4 sibling with notes on the F# implementation and its efficiency. Twelve modules.
Lists, recursion & complexity
Cons cells; big-O on .NET.
Trees & traversals
Binary and n-ary trees; DFS/BFS, functionally.
Sorting & searching
Merge/quick sort and binary search, immutably.
Maps, sets & hashing
Hash maps, collisions, the cost model.
Hash Array Mapped Tries (HAMT)
Persistent maps via prefix trees.
CHAMP maps
Compressed Hash-Array Mapped Prefix-trees; layout & iteration.
Identifiers, Snowflake & branded ids
From naive ids to a Snowflake bigint and a branded, base62 id.
Branded ids & persistence
Branded ids as keys in SQLite, PostgreSQL, and Redis.
Branded CHAMP maps & MailboxProcessor
A CHAMP keyed by branded ids, behind F#’s actor — the MailboxProcessor.
Practical recipes in F#
Turning algorithmic problems into idiomatic F#.
Dynamic programming & advanced problems
Overlapping subproblems, memoized and tabulated.
Lab: build a branded CHAMP store
An interactive lab: insert branded keys and watch the partitioned CHAMP restructure.
Pragmatic Programming — DevOps Tools
Ship a real F# DevOps tool end to end — the practical project and workshop, grounded in a working F#/.NET codebase. Nine modules.
Foundations
Start thin: a running tool and a clean solution layout from day one.
Modeling the domain
Log records, releases & hosts as records and discriminated unions.
The pure analysis core
Parsing and aggregation as pure F# — the library at the centre.
Server-side HTML in F#
The host: rendering HTML without templates or a framework.
A JSON API & external integration
Talking to an external service; auth and polling in F#.
Fable — F# to JavaScript on the client
One language across the wire; no Node bundler, no TypeScript.
Pragmatic testing
Testing the pure core with xUnit; properties over examples.
Packaging & deployment
A Dockerfile, a single-file publish, and going live.
Workshop: ship the DevOps dashboard
The capstone: assemble the tool end to end and deploy it.