From 4d55e4af9c6dcaf7394b3ee2d1241bff306c6d55 Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Mon, 3 Aug 2026 19:40:55 +0200 Subject: [PATCH 1/2] feat: showcase library effects, structs, and termination checking Co-Authored-By: Claude Fable 5 --- src/lib/indexExamples.js | 50 ++++++++++++++++ src/pages/index.astro | 126 ++++++++++++++++++++++++++++++++++----- 2 files changed, 161 insertions(+), 15 deletions(-) diff --git a/src/lib/indexExamples.js b/src/lib/indexExamples.js index ab946ad..171c3f5 100644 --- a/src/lib/indexExamples.js +++ b/src/lib/indexExamples.js @@ -100,6 +100,24 @@ def main(): Unit \\ IO = resume(dt.getHour()) }`; +export const libraryEffectsExample = `use Fs.FileRead +use Sys.Env +use Time.Clock +use Time.TimeUnit + +/// The \`Clock\`, \`Env\`, \`FileRead\`, and \`Logger\` +/// effects all have default handlers, hence \`main\` +/// requires no explicit handlers. +def main(): Unit \\ { Clock, Env, FileRead, Logger } = + let ts = Clock.currentTime(TimeUnit.Milliseconds); + let os = Env.getOsName(); + Logger.info("Timestamp: \${ts}"); + Logger.info("Operating System: \${os}"); + match FileRead.read("data.txt") { + case Ok(content) => Logger.info("Read: \${content}") + case Err(err) => Logger.warn("Error: \${err}") + }`; + export const regionExample = `/// /// We can implement a *pure* \`sort\` function which /// internally converts an immutable list to an array, @@ -125,6 +143,25 @@ def toString(l: List[a]): String with ToString[a] = StringBuilder.toString(sb) }`; +export const structsExample = `struct Person[r] { + name: String, + mut age: Int32 +} + +mod Person { + /// Creates a fresh \`Person\` in the region \`rc\`. + pub def mkPerson(name: String, rc: Region[r]): Person[r] \\ r = + new Person @ rc { name = name, age = 0 } + + /// Increments the age of the given person \`p\`. + pub def birthday(p: Person[r]): Unit \\ r = + p->age = p->age + 1 + + /// Returns a description of the given person \`p\`. + pub def describe(p: Person[r]): String \\ r = + "\${p->name} is \${p->age} years old" +}`; + export const purityReflectionExample = `/// /// We can inspect the purity of a function argument. /// @@ -264,6 +301,19 @@ def main(): Unit \\ IO = println("Unable to write file") }`; +export const terminationExample = `enum Tree[a] { + case Leaf(a) + case Node(Tree[a], Tree[a]) +} + +/// The compiler verifies that \`size\` is structurally +/// recursive and hence terminates on all inputs. +@Terminates +def size(t: Tree[Int32]): Int32 = match t { + case Tree.Leaf(_) => 1 + case Tree.Node(l, r) => size(l) + size(r) +}`; + export const datalogExample = `def reachable(g: List[(String, Int32, String)], minSpeed: Int32): List[(String, String)] = let facts = inject g into Road/3; let rules = #{ diff --git a/src/pages/index.astro b/src/pages/index.astro index 73c58e4..8adea9d 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -9,7 +9,9 @@ import { purityExample, polyEffectsExample, effectsExample, + libraryEffectsExample, regionExample, + structsExample, purityReflectionExample, parallelismExample, concurrencyExample, @@ -20,6 +22,7 @@ import { monadicForExample, applicativeForExample, javaInteropExample, + terminationExample, datalogExample, latticeExample, } from "../lib/indexExamples.js"; @@ -87,6 +90,9 @@ const vscodeSlides = [
+
+ +
@@ -101,15 +107,9 @@ const vscodeSlides = [
-
- -
-
- -
@@ -119,9 +119,15 @@ const vscodeSlides = [
+
+ +
+
+ +
@@ -137,15 +143,9 @@ const vscodeSlides = [
-
- -
-
- -
@@ -161,9 +161,15 @@ const vscodeSlides = [
+
+ +
+
+ +
@@ -178,7 +184,7 @@ const vscodeSlides = [ handlers enable program reasoning, modularity, and testability.

- For example, the program on the right expresses a greeting function that is pure modulo the current time of the day. In main

+
+ +
- +
+
+

Library Effects

+

+ The Flix Standard Library comes with a rich collection of + built-in effects, including Clock, Console, Env, FileSystem, Http, Logger, Process, and Random. +

+

+ Every library effect has a default handler, hence programs can + use them without any handler boilerplate. +

+

+ Library effects support composable middleware: HTTP requests can + be configured with retries and circuit breakers, and the + filesystem can be sandboxed, made read-only, or replaced with an + in-memory implementation, e.g. for testing. +

+
+
+
+
+
+
+ +
@@ -219,8 +255,34 @@ const vscodeSlides = [
+
+ +
- +
+
+

Mutable Structs

+

+ Flix supports mutable scoped structs. Fields are immutable by + default, but can be marked with the mut modifier. + Like all mutable memory in Flix, every struct belongs to a + region. +

+

+ Struct fields are unboxed, i.e. primitive fields do not require + indirection. This makes structs a memory efficient building + block for higher-level data structures, e.g. mutable lists, + stacks, and queues. +

+

+ The fields of a struct are only visible from within its + companion module, providing compiler-enforced encapsulation. +

+
+
+
+
+
@@ -465,6 +527,31 @@ const vscodeSlides = [
+
+
+ +
+
+
+
+

Termination Checking

+

+ Flix supports the @Terminates annotation, which + asks the compiler to verify that a function is structurally + recursive — and hence guaranteed to terminate on all + inputs. +

+

+ The compiler checks that every recursive call is on a strict + substructure of a formal parameter. The check supports tree + recursion, functions with multiple parameters, local + definitions, and higher-order functions. +

+
+
+
+
+
@@ -541,6 +628,7 @@ const vscodeSlides = [
  • extensible records
  • parametric polymorphism
  • traits (i.e. type classes)
  • +
  • automatic trait derivation
  • higher-kinded types
  • associated types and effects
  • @@ -548,6 +636,7 @@ const vscodeSlides = [
    • effect polymorphism + subeffecting
    • +
    • default effect handlers
    • purity reflection
    • CSP-style concurrency
    • buffered & unbuffered channels
    • @@ -561,6 +650,7 @@ const vscodeSlides = [
      • monadic forM expressions
      • applicative forA expressions
      • +
      • string interpolation
      • expression holes
      • compilation to JVM bytecode
      • full tail call elimination
      • @@ -850,6 +940,12 @@ const vscodeSlides = [ utop ghci + + Test Framework + flix + OUnit, alcotest + HUnit, tasty + Build Tool flix From 29f91ddb95b989d831590da4521cd8c605dd4b3f Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Mon, 3 Aug 2026 19:43:49 +0200 Subject: [PATCH 2/2] fix: say mutable structs instead of mutable scoped structs Co-Authored-By: Claude Fable 5 --- src/pages/index.astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/index.astro b/src/pages/index.astro index 8adea9d..e056be6 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -263,7 +263,7 @@ const vscodeSlides = [

        Mutable Structs

        - Flix supports mutable scoped structs. Fields are immutable by + Flix supports mutable structs. Fields are immutable by default, but can be marked with the mut modifier. Like all mutable memory in Flix, every struct belongs to a region.