Advanced Programming

in F#

ITT8060 Advanced Programming · Autumn 2026

Tallinn University of Technology

Lightning tour of F# as prose: notes.html

ITT8060

Welcome to Advanced Programming in F#

Course team: Juhan Ernits · Hendrik Maarand · Ian Erik Varatalu · Kermo Kütsen (teaching assistant)

Contact: hendrik.maarand@taltech.ee — mention ITT8060 in the subject line.

Course page: fsharp.pages.taltech.ee

Moodle (gradebook, recordings, homework feedback): moodle.taltech.ee/course/view.php?id=38067

Teams: the link to the team is announced now and posted in Moodle.

ITT8060

Textbooks

Recommended

Scott Wlaschin: Domain Modeling Made Functional — via O'Reilly library access with your uniid@taltech.ee address.

Don Syme, Adam Granicz, Antonio Cisternino: Expert F# 4.0 — via O'Reilly, as above.

Michael R. Hansen, Hans Rischel: Functional Programming Using F# — e-book at the TalTech library (Uni-ID login).

Supplementary

Tomas Petricek with Jon Skeet: Real-World Functional Programming (2010) — copies at the TalTech library. More at fsharp.org/learn.

ITT8060

Structure of the course

The course runs for 16 weeks. Each week a new topic in the lecture, then a practical session where you start on the homework.

Times and rooms: the timetable. Lectures are recorded.

The course is also offered as a Euroteq course; remote participation details are in Moodle.

This week's lab: sort out your Uni-ID (pass.taltech.ee), access to Moodle and GitLab, and see how automated test results are reported.

ITT8060

Assessment

Homework — 9 assignments × 4 points = 36%. Automated tests in your GitLab repository, plus oral defenses.

Midterm — week 9 (week of October 26, 2026), during the lecture, in person: 4%. You need to be there.

Exam — written, in person: 60%. At least half of the exam points are required to pass.

Grade scale: 91–100 → 5 · 81–90 → 4 · 71–80 → 3 · 61–70 → 2 · 51–60 → 1.

A bonus homework is planned for week 14.

ITT8060

Homework defenses

Every homework is tested automatically — and you must be able to explain your solution.

Defense required: homeworks 1, 4, 5 and 6. Passing these defenses is a prerequisite for admission to the exam.

Defense by random sampling: homeworks 2, 3, 7, 8 and 9 — a subset of submissions is called each round, so be prepared to defend any homework you submit.

A genuine effort trail with shortcomings → you get a chance to fix them.

No effort trail, or answers you cannot explain → the homework is not accepted, whatever the tests say.

ITT8060

Use of AI tools

An AI assistant can produce a passing solution to every homework in this course. Passing tests therefore prove nothing about your learning — the defenses do.

Homework: AI tools are allowed as learning aids — explain a concept, explore an alternative, decode an error message. Solve it yourself first. The submission must reflect your own understanding: you explain, justify and modify any part of it on request.

Effort trail: develop in your homework repository with honest, incremental commits.

Midterm and exam: written in person, no AI tools.

Full policy: syllabus → Academic Practices → Use of AI Tools.

ITT8060

Why this course

and why F#

ITT8060

Why this course

In AI-assisted software development, producing code has become cheap.

What remains scarce:

  • stating precisely what a program must do,
  • modeling the domain so that incorrect programs are hard to express,
  • verifying that the result is correct.

Functional programming in F# trains you to think in types, transformations, invariants and effects — the skills you need to specify, review and supervise software regardless of who, or what, writes the code.

Correctness and clearly expressed intent matter more than typing speed.

ITT8060

Course goals

Think and program functionally: clean, well-structured programs whose correctness can be argued from their types and structure.

Model domains with types — discriminated unions and records that make the valid states explicit, so the compiler complains the moment code and intent diverge.

Build from pure, composable functions with visible effects — easier to reason about, test and safely modify, whoever makes the change.

Recognize where a functional approach is natural — and tell functional from imperative style in any language.

Test functional programs, including property-based testing; meet asynchronous and parallel programming in the functional setting.

ITT8060

You can all write programs!

What was your first programming language?

Python · Java · C · C++ · C# · JavaScript · TypeScript · PHP · Kotlin · Swift · Scratch · Pascal · Basic · …

Was it functional?

Elixir · Erlang · Clojure · Racket · Haskell · OCaml · F# · Scala · Lean · Idris · Agda · Prolog · Whitespace · …

ITT8060

Why F# — of the many functional languages?

Kotlin · Scala · Elixir · Erlang · Common Lisp · Clojure · Racket · Scheme · Haskell · Agda · Idris · OCaml · even C++ with the STL …

Most of them would teach the same ideas. F# lets us teach them in a language that is

  • functional-first, not functional-only — objects and mutation are there when they fit;
  • industrially supported, on .NET — every library of the platform is one open away;
  • eagerly evaluated and strongly typed, in the ML family — type inference does most of the typing for you.
ITT8060

F#

An industrially supported, functional-first .NET language.

Member of the eagerly evaluated ML family; closest relative: OCaml.

Integrates into existing .NET projects — C# code calls F# code without noticing.

F# is well designed. Did you read the paper?

Don Syme, The Early History of F#, HOPL IV, 2020 — doi.org/10.1145/3386325

In 2026 we use F# 10 on .NET 10. Course examples may use anything introduced up to that version.

ITT8060

Models of computation

what versus how

ITT8060

Imperative models

Computation is expressed in terms of a state and a sequence of state-changing operations.

i := 0; s := 0;
while i < length(A) do
    s := s + A[i];
    i := i + 1
od

An imperative model describes how a solution is obtained.

ITT8060

Object-oriented models

An object is characterized by a state and an interface: a collection of state-changing operations.

Object-oriented models are expressed as collections of objects exchanging messages through their interfaces.

Object orientation adds structure to imperative models —

but an object-oriented model still describes how a solution is obtained.

ITT8060

Declarative models

Focus is on what a solution is.

Logic programming — programs are formulas in a fragment of first-order logic, with a procedural reading based on inference.

Functional programming — a program is a mathematical function \(f : A \to B\), and function application guides the computation.

Some advantages: fast prototyping from abstract concepts · more advanced applications within reach · a complement to modeling and problem-solving techniques · runs in parallel on multi-core machines.

(Michael R. Hansen, 02157 Functional Programming, lecture 1)

ITT8060
IEnumerable<string> GetExpensiveProducts() {
  var infos = new List<string>();
  foreach (var product in Products) {
    if (product.UnitPrice > 75.00M) {
      infos.Add(String.Format("{0} - ${1}",
        product.ProductName,
        product.UnitPrice));
    }
  }
  return infos;
}

Imperative style

A growing list, a loop, a condition, an Addstate-changing operations.

To learn what comes out, you simulate the machine in your head.

ITT8060
IEnumerable<string> GetExpensiveProducts() =>
  from product in Products
  where product.UnitPrice > 75.0M
  select String.Format("{0} - ${1}",
    product.ProductName,
    product.UnitPrice);

Declarative style

Says what the result is: the expensive products, formatted.

Same language, same runtime — a different model of computation.

LINQ (2007) is functional programming in C#'s clothes.

ITT8060

The same idea in F#

from product in Products
where product.UnitPrice > 75.0M
select String.Format("{0} - ${1}",
  product.ProductName,
  product.UnitPrice)
products
|> List.filter (fun p -> p.UnitPrice > 75.0M)
|> List.map (fun p ->
    $"{p.ProductName} - ${p.UnitPrice}")

A pipeline: the data flows left to right through filter and map. Each stage is a function; nothing is mutated.

You will write this shape hundreds of times this semester.

ITT8060

Convenient parallelisation

var updated =
  from m in monsters
  let nm = m.PerformStep()
  where nm.IsAlive
  select nm;
var updated =
  from m in monsters.AsParallel()
  let nm = m.PerformStep()
  where nm.IsAlive
  select nm;

LINQ on the left, PLINQ on the right: no shared state to protect, so one method call makes it parallel.

The payoff of declarative style: when you say what, the runtime may choose how.

ITT8060

A bit of history

from the λ-calculus to .NET

ITT8060

The λ-calculus and LISP

The model of computation in functional programming: application of functions to arguments — no side effects.

≈1930 — Church and Kleene introduce the λ-calculus while investigating function definition, application, recursion and computable functions.

\(f(x) = x + 2\) is written \(\lambda x.\, x + 2\).

Late 1950s — McCarthy's LISP: a type-less, functional-like language, used for AI problems.

ITT8060

The Curry–Howard correspondence

1934 — Haskell Curry observes that the types of the combinators can be read as axiom schemes of intuitionistic implicational logic.

1958 — Curry: a Hilbert-style proof system coincides, on a fragment, with the typed part of combinatory logic.

1969 — Howard: natural deduction, in its intuitionistic version, is a typed variant of the λ-calculus.

Types are propositions, programs are proofs. That is why a compiler can check what you meant — and why week 15 visits Lean.

ITT8060

From FP to ML

1977 — Backus' FP: a "variable-free" language built from a rich collection of functionals (combining forms for functions).

1970s — languages with strong type systems: ML (Milner) and Miranda (Turner).

Standard ML was designed for theorem proving: Logic for Computable Functions, Edinburgh LCF — Gordon, Milner, Wadsworth, 1977.

High-quality compilers built on a formal semantics: Standard ML of New Jersey, Moscow ML — Milner, Tofte, Harper, MacQueen, 1990 and 1997.

ITT8060

The ML family today

SML-like systems (SML, OCaml, F#, …) are used far from their origins: compilers, artificial intelligence, data analysis, web applications, finance, mobile apps …

F# is a .NET language: The .NET Language Strategy.

Declarative features keep sneaking into the "mainstream" languages — LINQ, Java streams, pattern matching in C# and Python …

… and the ML family is often used to teach high-level programming concepts. Here too.

ITT8060

One idea that travelled

F# was the first language to introduce an async modality to allow the localized reinterpretation of the existing control constructs of the language. Converting a piece of code from synchronous to asynchronous involved nothing more than wrapping async { ... } around the code and marking up the await points (let! in F#). This directly influenced the async/await mechanism added to C# 5.0 in 2012.

The C# async/await feature has been influential on TypeScript, Kotlin, Python 3.5, Java, JavaScript and other languages.

(Don Syme, The Early History of F#, 2020)

ITT8060

What you will meet

concepts, and two things F# people actually do

ITT8060

Some concepts you will meet in ITT8060

functions and modules, higher-order functions · pipelines and composition · lists, arrays, sequences · pattern matching and active patterns · type inference

recursive functions and tail recursion · records and discriminated unions · option types · error handling by types · units of measure · property-based testing

object programming · asynchronous programming · computation expressions · type providers · quotations

Nearly all of them have counterparts in your other languages. Here you learn them where they are native.

ITT8060
#r "nuget: FSharp.Data"
open FSharp.Data

[<Literal>]
let sample = """{ "data": [
  { "subject": "ITT8060",
    "room": "ICO-221",
    "start": "2026-08-31T10:00:00" } ] }"""

type Timetable = JsonProvider<sample>

for e in (Timetable.Parse sample).Data do
  printfn "%A %s %s" e.Start e.Room e.Subject

Why I use F#

A JSON sample becomes a type at compile time: e.Start is a DateTime, e.Room a string.

Misspell a field and the compiler tells you — before anything runs.

Types as specifications in daily work. Type providers: week 14.

ITT8060

Can anything exciting be done in F#?

RE# — a derivative-based regular expression engine written in F# by Ian Erik Varatalu, and the fastest around on the standard benchmarks: cs.taltech.ee/staff/iavara/regex

Why it is fast: the paper at arxiv.org/abs/2407.20479.

Source: github.com/ieviev/resharp

ITT8060

Lightning introduction to F#

Now: VS Code, F# Interactive, and a first script — let, functions, tuples, pipelines, recursion, strings, and calling .NET.

Follow along in the notes: notes.html. The script is 01-introduction.fsx in course-materials.

Reading for this week: Hansen & Rischel, chapter 1; Wlaschin, part I.

Lab: Uni-ID, Moodle, GitLab — and a look at how automated tests report.

ITT8060