{"id":50811979,"url":"https://github.com/kiquetal/fsharp-workout","last_synced_at":"2026-06-13T05:33:38.046Z","repository":{"id":347821534,"uuid":"1194901589","full_name":"kiquetal/fsharp-workout","owner":"kiquetal","description":"Hands-on F# training — 6 hyperfocus sessions covering type-driven design, pipelines, pattern matching, domain modeling, async, and integration","archived":false,"fork":false,"pushed_at":"2026-05-26T15:07:13.000Z","size":162,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T17:09:19.638Z","etag":null,"topics":["domain-modeling","dotnet","fsharp","functional-programming","hyperfocus-training","type-driven-design"],"latest_commit_sha":null,"homepage":"","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kiquetal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-29T00:43:49.000Z","updated_at":"2026-05-26T15:16:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kiquetal/fsharp-workout","commit_stats":null,"previous_names":["kiquetal/fsharp-workout"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kiquetal/fsharp-workout","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Ffsharp-workout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Ffsharp-workout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Ffsharp-workout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Ffsharp-workout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kiquetal","download_url":"https://codeload.github.com/kiquetal/fsharp-workout/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kiquetal%2Ffsharp-workout/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34273788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-13T02:00:06.617Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["domain-modeling","dotnet","fsharp","functional-programming","hyperfocus-training","type-driven-design"],"created_at":"2026-06-13T05:33:36.811Z","updated_at":"2026-06-13T05:33:38.031Z","avatar_url":"https://github.com/kiquetal.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# F# Hyperfocus Training\n\nA structured, hands-on F# training program designed for deep-focus sessions. Each session is **90 minutes max** — short enough to stay in flow, long enough to build something real.\n\n## Philosophy\n\n- **Type-first thinking** — design with types before writing logic\n- **Learn by building** — every session produces working code\n- **Progressive complexity** — each session builds on the previous one\n- **No fluff** — pure practice, no slides\n\n## Schedule\n\n| # | Session | Focus | Duration | Status |\n|---|---------|-------|----------|--------|\n| 1 | **Types as Design** | Records, DUs, single-case wrappers, making illegal states unrepresentable | 90 min | ✅ Done |\n| 2 | **Pipelines \u0026 Composition** | `\\|\u003e`, `\u003e\u003e`, `Option`, `Result`, railway-oriented error handling | 90 min | ✅ Done |\n| 3 | **Pattern Matching \u0026 Recursion** | Exhaustive matching, active patterns, recursive data structures | 90 min | ✅ Done |\n| 4 | **Modules \u0026 Domain Modeling** | Module design, encapsulation, a small bounded context end-to-end | 90 min | ✅ Done |\n| 5 | **Collections \u0026 Pipelines** | `List.map`, `List.groupBy`, `List.collect`, pipeline composition with `\\|\u003e` and `\u003e\u003e` | 90 min | ✅ Done |\n| 6 | **Integration \u0026 Capstone** | JSON serialization, HTTP, CLI app — tie everything together | 90 min | ✅ Done |\n\n## Part II — State Machines \u0026 Data Transformation\n\n| # | Session | What you build | Key concept |\n|---|---------|---------------|-------------|\n| 7 | **Explicit State Machines** | A deployment pipeline (Pending → Building → Testing → Deployed / Failed) | DUs as states, transition functions that only accept valid moves |\n| 8 | **Event Sourcing from Scratch** | An order lifecycle — rebuild current state by replaying events | Events as DUs, state = fold over event list |\n| 9 | **Parsing \u0026 Transformation** | A log file parser — raw text → structured records → summary report | Active patterns, `Result` chains, pipeline composition |\n| 10 | **Recursive Data Structures** | A file system tree or config hierarchy — traverse, transform, flatten | Trees as recursive DUs, catamorphisms (folds over trees) |\n| 11 | **Workflow Engine** | A multi-step approval process with branching and rollback | Combining state machines + event sourcing |\n| 12 | **Capstone: Infrastructure DSL** | A small DSL that describes infrastructure and validates it at compile time | Computation expressions, type-safe builders |\n\n### Progression\n\n- **Session 7** teaches the raw pattern — a state machine is just a function `State → Event → State`\n- **Session 8** shows that storing events gives you time travel for free (replay, audit, debugging)\n- **Sessions 9–10** build transformation muscles — taking messy data and shaping it\n- **Session 11** combines both skills into something real\n- **Session 12** ties it to systems engineering — building a tiny infrastructure DSL (think mini Pulumi/Terraform in F#)\n\n### Where Temporal fits in\n\nAfter building state machines by hand (Sessions 7–8), you'll understand what tools like [Temporal](https://temporal.io) abstract away:\n- **F# state machines** = the logic (which transitions are valid, compile-time safety)\n- **Temporal** = the runtime (durable execution, retries, surviving crashes across distributed services)\n\n## Sessions\n\n### Session 1 — Types as Design ✅\n\n**Objective:** Encode domain rules in the type system so invalid states can't exist.\n\n**What you learned:**\n- Records for data, discriminated unions for choices\n- Single-case DUs with `private` as domain primitives (`Quantity`, `OrderNumber`)\n- Smart constructors — validate once at the boundary, trust the types after\n- `Result\u003c'T, 'E\u003e` for expected failures instead of exceptions\n- Units of measure for compile-time dimensional safety\n\n→ [Full details](docs/session01.md)\n\n### Session 2 — Pipelines \u0026 Composition ✅\n\n**Objective:** Chain fallible operations cleanly, accumulate errors, and compose processing pipelines.\n\n**What you learned:**\n- `bind`, `map2`, `apply` — the Result combinators that replace nested matching\n- Applicative validation — collect ALL errors instead of stopping at the first\n- Active patterns — custom decompositions for readable `match` expressions\n- Pipeline composition with `|\u003e` from validation through pricing\n- Batch processing — partition successes and failures across a list\n\n→ [Full details](docs/session02.md)\n\n### Session 3 — Pattern Matching \u0026 Recursion ✅\n\n**Objective:** Exhaustive matching, recursive data structures, and generic folds.\n\n**What you learned:**\n- Recursive DU types (`Expr` — a type that references itself)\n- Structural recursion — one match branch per DU case\n- `evaluate` with `Result.bind` for railway-oriented recursion\n- `format` for recursive pretty-printing\n- `simplify` for tree transformation (algebraic rules)\n- Generic `fold` (catamorphism) — extracting the common recursion pattern\n- Factory worker analogy — each branch node combines finished results from below\n\n→ [Full details](docs/session03.md)\n\n### Session 4 — Modules \u0026 Domain Modeling ✅\n\n**Objective:** Organize domain logic into modules with clear boundaries.\n\n**What you learned:**\n- Module design — group related functions, each module validates what it owns\n- `Book` module — status transitions (Available ↔ CheckedOut)\n- `Member` module — borrow limits, duplicate checks\n- `Library` module — orchestration, calling Book + Member and combining results\n- Record updates with `{ x with ... }` — immutable state transitions\n- `Map` as in-memory storage — `tryFind`, `add`, `filter`, `values`\n- Query functions — `availableBooks`, `booksBorrowedBy`\n- Domain vs storage separation — domain stays pure, repository translates\n\n→ [Full details](docs/session04.md)\n\n### Session 5 — Collections \u0026 Pipelines ✅\n\n**Objective:** Master F#'s collection functions and pipeline composition.\n\n**What you learned:**\n- `List.map`, `List.filter`, `List.sumBy` — basic transformations\n- `List.collect` — flatMap for F#, use when your lambda returns a list\n- `List.groupBy` — group items by key, returns `(key * items) list`\n- `List.sortByDescending`, `List.truncate` — ranking and limiting\n- `List.choose` — map + filter in one step using `Option`\n- `snd` / `fst` — extract tuple elements\n- `\u003e\u003e` composition — build reusable pipelines without data\n- `|\u003e` vs `\u003e\u003e` — \"run now\" vs \"save for later\"\n\n→ [Full details](docs/session05.md)\n\n### Session 6 — Integration \u0026 Capstone ✅\n\n**Objective:** Tie together everything from Sessions 1–5 into one cohesive CLI application.\n\n**What you built:**\n- Weather Station Dashboard — parse, validate, analyze, report\n- `Parsing` module — safe string parsing with `TryParse`, `parseAll` with partition\n- `Validation` module — business rules on top of smart constructors\n- `Analytics` module — `averageBy`, `groupBy`, `minBy`/`maxBy`, daily aggregates\n- `Report` module — formatted output, per-station summaries, error reporting\n- Smart constructors with `private` DUs for `Temperature` and `Humidity`\n- Full pipeline: raw strings → typed data → validated data → analytics → report\n\n→ [Full details](docs/session06.md)\n\n## Session Format\n\nEach 90-minute session follows this rhythm:\n\n```\n[0:00 - 0:10]  Concept intro — read the brief, understand the types\n[0:10 - 0:60]  Build — implement the exercise, iterate\n[0:60 - 0:80]  Stretch goal — extend or refactor\n[0:80 - 0:90]  Review — reflect, commit, note what clicked\n```\n\n## Project Structure\n\n```\nsrc/\n  Session01/       ← Types as Design\n  Session02/       ← Pipelines \u0026 Composition\n  Session03/       ← Pattern Matching \u0026 Recursion\n  Session04/       ← Modules \u0026 Domain Modeling\n  Session05/       ← Collections \u0026 Pipelines\n  Session06/       ← Integration \u0026 Capstone\ndocs/\n  session01.md     ← Full session 1 details, exercises, concepts\n  session02.md     ← Full session 2 details, exercises, concepts\n  session03.md     ← Full session 3 details, exercises, concepts\n  session04.md     ← Full session 4 details, exercises, concepts\n  session05.md     ← Full session 5 details, exercises, concepts\n  session06.md     ← Full session 6 details, exercises, concepts\n  patterns.md      ← Railway-oriented programming, parse don't validate\n  java21-functional.md ← F# patterns translated to Java 21+\n  learning-notes.md    ← Validation boundaries, complex types, Result.sequence\ntests/             ← Test projects (optional, on demand)\n```\n\n## Getting Started\n\n```bash\n# Build all projects\ndotnet build\n\n# Run a specific session\ndotnet run --project src/Session01\n\n# Run with watch (auto-reload on save)\ndotnet watch run --project src/Session01\n\n# Build and run the full solution\ndotnet build FSharpWorkout.sln\n```\n\n## Rules for Yourself\n\n1. **No mutable variables** — if you reach for `mutable`, rethink\n2. **No exceptions for expected failures** — use `Result`\n3. **Types before functions** — define the domain types first, then the transformations\n4. **Commit after each session** — track your progress\n\n## Reference Docs\n\n- [Patterns worth studying](docs/patterns.md) — railway-oriented programming, making illegal states unrepresentable, parse don't validate\n- [F# → Java 21+ translation](docs/java21-functional.md) — map/flatMap, sealed interfaces, smart constructors, Stream pipelines\n- [Learning notes](docs/learning-notes.md) — validation boundaries, complex types example, Result.sequence vs validation\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiquetal%2Ffsharp-workout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkiquetal%2Ffsharp-workout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkiquetal%2Ffsharp-workout/lists"}