Language basics
27 steps in 9 sets of F#.
F# is the .NET family's functional-first language: OCaml's lineage running on the CLR, with the entire NuGet ecosystem one open statement away. Immutability is the default, the compiler infers nearly every type, and the pipeline operator turns data transformations into sentences that read forward. Finance shops, data teams, and web backends (Giraffe, the SAFE stack) run it in production, and its scripting form — .fsx files under dotnet fsi — makes it one of the most pleasant REPL languages on any runtime.
This tour types the functional core: let bindings with deliberate mutability, the three string-building idioms, currying and partial application, pipelines and composition, match with guards, Option and Result with their module pipelines, active patterns, cons-built lists and the List module, folds, records with copy-and-update, discriminated unions, Map and Set, groupBy, arrays against lazy sequences, tail recursion, exceptions, and the signature party trick — units of measure the compiler enforces. The Encore is the cross-language script trio in idiomatic F#: countBy, guarded matches, and pairwise.
Values
- The script shapeThe smallest F#: let bindings and printfn, top to bottom.
- let bindingsImmutable by default; mutable is a separate, spelled-out choice.
- Strings three waysprintfn formats, sprintf returns, $-interpolation splices.
Functions
- CurryingEvery function takes one argument; partial application is free.
- The pipeline|> feeds the left value forward; data reads in flow order.
- Composition>> glues functions into new functions, no argument named.
Pattern matching
- matchAn expression that must cover every case; the compiler audits.
- OptionAbsence spelled Some or None — there is no null to forget.
- Active patternsName a classification once; match on it like a built-in.
Lists
- Lists and consImmutable, singly linked: :: builds, @ appends, patterns split.
- The List modulemap, filter, sortBy, sumBy: the daily toolkit.
- fold and reduceThread state through a list; the accumulator can be anything.
Types
- RecordsImmutable named bundles with structural equality built in.
- Discriminated unionsA closed set of shapes; match must cover them all.
- TuplesPair values without ceremony; patterns take them apart.
Collections
- Map and SetImmutable keyed and unique collections; adds return new ones.
- groupBy and countByBucket a list by computed key, then fold each bucket.
- Arrays and seqsArrays index and mutate; seqs are lazy views over anything.
Idioms
- ResultOk or Error, and bind to keep the pipeline on the happy track.
- Recursionrec allows self-reference; an accumulator keeps calls in tail position.
- Option pipelinesmap, filter and defaultValue chain maybes with no null checks.
Signatures & laziness
- Exceptionstry/with catches by pattern; failwith raises with a message.
- Units of measurekg and jar ride the type system; wrong units will not compile.
- Lazy sequencesInfinite is fine until something pulls.
Encore
- word_freq.fsxA word-frequency table from Split, countBy, and one two-key sort.
- grade_report.fsxReport cards from a record roster, a guarded match, and printf columns.
- temp_stats.fsxA week of temperatures: minBy/maxBy, a bar chart, and pairwise swings.