Skip to content
learn

F# for C#/Java developers — Mission

You write C# or Java. You have used lambdas, LINQ or streams, records, maybe switch expressions with patterns. F# takes those ideas, which C# and Java borrowed from functional languages over the last fifteen years, and makes them the default: values that don’t change, functions that return values instead of changing state, types that describe every case of your data, and a compiler that checks that you handled all of them.

F# runs on .NET, calls every .NET library, and compiles to the same intermediate language as C#. You don’t have to leave your ecosystem to learn it, and what you learn changes how you write C#.

This course uses the current versions: F# 10, which ships with .NET 10, released in November 2025.

The examples come from two public F# code bases, pinned on a commit so that the links keep pointing at the code the lessons describe:

  • TARS, an F# agent framework (reasoning, multi-agent workflows, probabilistic grammars), at commit 87464ce. Its active code lives in v2/: the lessons only cite projects that its solution v2/Tars.sln builds and that its CI tests.
  • Guitar Alchemist (GA), a music theory application written mostly in C#, whose music DSL, parsers, configuration and language server are in F#, at commit 32f143c.

When an extract of GA compiles on its own, the course keeps a copy of the file in code/fsharp/external/ga (GA is under the MIT license) and runs it. TARS has no license file, so its code is linked and quoted, and reproduced in a few lines only where a behavior needs to be shown. What the lessons find in these repositories (a bug, dead code, a script that doesn’t run) goes in the journal.

Each lesson starts from what you would write in C# (and in Java when it differs), then:

  1. the F# way, with a short script and the output it really printed;
  2. the compiler’s view: the errors and warnings you will meet, with their exact message;
  3. real code from TARS or GA that uses the notion;
  4. exercises, with a solution under Solution: try first, then open it.

By the end of this course, I will be able to

Section titled “By the end of this course, I will be able to”
  • run F# scripts and F# Interactive, and organize an F# project whose files compile in order;
  • model a domain with records, discriminated unions and options, so that invalid states don’t compile;
  • write functions that compose, with pipelines, partial application and exhaustive pattern matching;
  • handle errors with Result, and write and read computation expressions, including my own;
  • test F# code with xUnit, FsCheck and Expecto, and parse text with FParsec;
  • measure and reduce allocations, and choose between Async, Task and MailboxProcessor;
  • read and extend a real F# code base, and publish an F# library that C# code consumes comfortably.
# Lesson Notions Real code
Beginner
1 Scripts, F# Interactive and projects dotnet fsi, .fsx scripts, printfn, #r "nuget:", indentation, the file order of a .fsproj GA’s GA.Business.DSL.fsproj and Scripts/ModesConfig.fsx, TARS’s Tars.Core.fsproj
2 Values, functions and type inference let, immutability, mutable, inference, currying, partial application, |> and >>, expressions everywhere GA’s HarmonicTransformationService, TARS’s TextNormalizer
3 Tuples, records, unions and options tuples, records and with, discriminated unions, Option, single-case unions, RequireQualifiedAccess GA’s ChordAst, TARS’s Domain.fs and Primitives.fs
4 Pattern matching match, guards, or-patterns, list and record patterns, exhaustiveness warnings GA’s ChordRenderer, ChordParser and BinObj.fsx, TARS’s AgentWorkflow.fs
5 Lists, arrays and sequences List, Array and Seq modules, pipelines next to LINQ and streams, laziness
6 Modules, namespaces and project organization modules, namespaces, private and internal, signature files
Intermediate
7 Errors with Result railway-oriented programming, Result next to exceptions
8 Computation expressions — a parser for a DSL seq, async, task, builders, Bind, Return, a parser CE and explicit end-of-input GA’s music DSL
9 Objects in F# classes, interfaces, object expressions, calling C# libraries
10 Testing xUnit, FsCheck property-based tests, Expecto
11 Parsers FParsec and hand-written combinators GA’s music DSL
12 Modeling a domain units of measure, phantom types, making illegal states unrepresentable TARS’s Budget
Advanced and expert
13 Custom computation expressions builders, let! and and!, what the compiler generates TARS’s AgentWorkflow
14 Type providers — typed data from a sample erased and generative providers, CSV and JSON inference, schema stability FSharp.Data
15 Performance structs, inline, Span, voption, allocations measured with BenchmarkDotNet
16 Concurrency MailboxProcessor, Async next to Task, channels
17 Metaprogramming Myriad, FSharp.Compiler.Service GA’s F# Interactive session pool
18 Tooling a language server in F#, Fantomas, analyzers GA’s GaMusicTheoryLsp
19 Architecture of a real F# application a guided reading of TARS TARS
20 Publishing an F# library for C# API design, [<CompiledName>], options and unions seen from C#
— Journal

Lessons 9–13 and 15–20 are planned and not written yet.