From 360ed0a1cd7cdeace8b4b48d5a6fea58c89f5b84 Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Sun, 23 Nov 2025 18:49:15 +0100 Subject: [PATCH 1/5] feat: default handlers --- src/SUMMARY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index fe09b1e2..4bb6682b 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -32,6 +32,7 @@ - [Effect Polymorphism](./effect-polymorphism.md) - [Effects and Handlers](./effects-and-handlers.md) - [Library Effects](./library-effects.md) + - [Default Handlers](./default-handlers.md) - [Effect-Oriented Programming](./effect-oriented-programming.md) - [Modules](./modules.md) - [Declaring Modules](./declaring-modules.md) From 547d56d819af5e9053c30175696f2b01ec08a8b0 Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Sun, 23 Nov 2025 18:49:19 +0100 Subject: [PATCH 2/5] feat: default handlers --- src/default-handlers.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/default-handlers.md diff --git a/src/default-handlers.md b/src/default-handlers.md new file mode 100644 index 00000000..606fea52 --- /dev/null +++ b/src/default-handlers.md @@ -0,0 +1,3 @@ +## Default Handlers + +Flix supports _default handlers_ which means that \ No newline at end of file From 211c227288672fcb5533b0ce10c53de7c962a868 Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Sun, 23 Nov 2025 20:38:16 +0100 Subject: [PATCH 3/5] work on default handlers --- src/default-handlers.md | 47 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/default-handlers.md b/src/default-handlers.md index 606fea52..a46219cc 100644 --- a/src/default-handlers.md +++ b/src/default-handlers.md @@ -1,3 +1,48 @@ ## Default Handlers -Flix supports _default handlers_ which means that \ No newline at end of file +Flix supports **default handlers** which means that an effect can declare a +handler that translate the effect into the `IO` effect. Then `main` or any +method marked `@Test` can use that effect without explicitly handling the +effect. + +For example, we can write: + +```flix +def main(): Unit \ {Clock, Env, Logger} = + let ts = Clock.currentTime(TimeUnit.Milliseconds); + let os = Env.getOsName(); + Logger.info("UNIX Timestamp: ${ts}"); + Logger.info("Operating System: ${os}") + +``` + +which the Flix compiler automatically translates into: + +```flix +def main(): Unit \ IO = + run { + let ts = Clock.currentTime(TimeUnit.Milliseconds); + let os = Env.getOsName(); + Logger.info("UNIX Timestamp: ${ts}"); + Logger.info("Operating System: ${os}") + } with Clock.runWithIO + with Env.runWithIO + with Logger.runWithIO +``` + +Notably `Clock.runWithIO`, `Env.runWithIO`, and `Logger.runWithIO` are the +default handlers for their respective effects. + +For example, `Clock.runWithIO` is declared as: + +```flix +@DefaultHandler +pub def runWithIO(f: Unit -> a \ ef): a \ (ef - Clock) + IO = ... +``` + +As the example shows, a default handler is declared with `@DefaultHandler` +annotation. An effect can have at most one default handler and it must be in the +companion module of the effect. + +> **Note:** A default handler must translate an effect to the `IO` effect. + From 64734d9523266ba4c69180193b135313584da1ae Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Sun, 23 Nov 2025 20:55:10 +0100 Subject: [PATCH 4/5] . --- src/default-handlers.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/default-handlers.md b/src/default-handlers.md index a46219cc..20393162 100644 --- a/src/default-handlers.md +++ b/src/default-handlers.md @@ -1,9 +1,9 @@ ## Default Handlers -Flix supports **default handlers** which means that an effect can declare a -handler that translate the effect into the `IO` effect. Then `main` or any -method marked `@Test` can use that effect without explicitly handling the -effect. +Flix supports **default handlers**, meaning an effect can declare a handler that +translates the effect into the `IO` effect. This allows `main` and any method +annotated with `@Test` to use that effect without explicitly providing a +handler. For example, we can write: @@ -40,9 +40,14 @@ For example, `Clock.runWithIO` is declared as: pub def runWithIO(f: Unit -> a \ ef): a \ (ef - Clock) + IO = ... ``` -As the example shows, a default handler is declared with `@DefaultHandler` -annotation. An effect can have at most one default handler and it must be in the -companion module of the effect. +A default handler is declared using the `@DefaultHandler` annotation. Each +effect may have at most one default handler, and it must reside in the companion +module of that effect. -> **Note:** A default handler must translate an effect to the `IO` effect. +> **Note:** A default handler must have the signature: +> +> ```flix +> runWithIO(f: Unit -> a \ ef): a \ (ef - E) + IO +> ``` +> where `E` is the name of the effect. From 38d55aa92c019ae13bbccb1fdb534c5ece05fe87 Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Sun, 23 Nov 2025 22:24:34 +0100 Subject: [PATCH 5/5] . --- book.toml | 1 - src/default-handlers.md | 37 ++++++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/book.toml b/book.toml index 5ac2de23..4c7e0067 100644 --- a/book.toml +++ b/book.toml @@ -1,7 +1,6 @@ [book] authors = ["Magnus Madsen"] language = "en" -multilingual = false src = "src" title = "Programming Flix" diff --git a/src/default-handlers.md b/src/default-handlers.md index 20393162..419dafa0 100644 --- a/src/default-handlers.md +++ b/src/default-handlers.md @@ -1,9 +1,11 @@ ## Default Handlers -Flix supports **default handlers**, meaning an effect can declare a handler that -translates the effect into the `IO` effect. This allows `main` and any method -annotated with `@Test` to use that effect without explicitly providing a -handler. +> **Note:** This feature requires Flix version 0.67.0 + +Flix supports **default handlers** which means that an effect can declare a +handler that translates the effect into the `IO` effect. This allows `main` (and +any method annotated with `@Test`) to use that effect without explicitly +providing a handler in a `run-with` block. For example, we can write: @@ -16,7 +18,7 @@ def main(): Unit \ {Clock, Env, Logger} = ``` -which the Flix compiler automatically translates into: +which the Flix compiler translates to: ```flix def main(): Unit \ IO = @@ -30,8 +32,9 @@ def main(): Unit \ IO = with Logger.runWithIO ``` -Notably `Clock.runWithIO`, `Env.runWithIO`, and `Logger.runWithIO` are the -default handlers for their respective effects. +That is, the Flix compiler automatically inserts calls to `Clock.runWithIO`, +`Env.runWithIO`, and `Logger.runWithIO` which are the default handlers for their +respective effects. For example, `Clock.runWithIO` is declared as: @@ -44,10 +47,18 @@ A default handler is declared using the `@DefaultHandler` annotation. Each effect may have at most one default handler, and it must reside in the companion module of that effect. -> **Note:** A default handler must have the signature: -> -> ```flix -> runWithIO(f: Unit -> a \ ef): a \ (ef - E) + IO -> ``` -> where `E` is the name of the effect. +A default handler must have a signature of the form: + +```flix +def runWithIO(f: Unit -> a \ ef): a \ (ef - E) + IO +``` +where `E` is the name of the effect. +We can use effects with default handlers in tests. For example: + +```flix +@Test +def myTest01(): Unit \ {Assert, Logger} = + Logger.info("Running test!"); + Assert.assertEq(expected = 42, 42) +```