Skip to content

Commit 1048163

Browse files
feat: add default-handlers.md (#272)
1 parent cb4923e commit 1048163

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

book.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[book]
22
authors = ["Magnus Madsen"]
33
language = "en"
4-
multilingual = false
54
src = "src"
65
title = "Programming Flix"
76

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
- [Effect Polymorphism](./effect-polymorphism.md)
3333
- [Effects and Handlers](./effects-and-handlers.md)
3434
- [Library Effects](./library-effects.md)
35+
- [Default Handlers](./default-handlers.md)
3536
- [Effect-Oriented Programming](./effect-oriented-programming.md)
3637
- [Modules](./modules.md)
3738
- [Declaring Modules](./declaring-modules.md)

src/default-handlers.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
## Default Handlers
2+
3+
> **Note:** This feature requires Flix version 0.67.0
4+
5+
Flix supports **default handlers** which means that an effect can declare a
6+
handler that translates the effect into the `IO` effect. This allows `main` (and
7+
any method annotated with `@Test`) to use that effect without explicitly
8+
providing a handler in a `run-with` block.
9+
10+
For example, we can write:
11+
12+
```flix
13+
def main(): Unit \ {Clock, Env, Logger} =
14+
let ts = Clock.currentTime(TimeUnit.Milliseconds);
15+
let os = Env.getOsName();
16+
Logger.info("UNIX Timestamp: ${ts}");
17+
Logger.info("Operating System: ${os}")
18+
19+
```
20+
21+
which the Flix compiler translates to:
22+
23+
```flix
24+
def main(): Unit \ IO =
25+
run {
26+
let ts = Clock.currentTime(TimeUnit.Milliseconds);
27+
let os = Env.getOsName();
28+
Logger.info("UNIX Timestamp: ${ts}");
29+
Logger.info("Operating System: ${os}")
30+
} with Clock.runWithIO
31+
with Env.runWithIO
32+
with Logger.runWithIO
33+
```
34+
35+
That is, the Flix compiler automatically inserts calls to `Clock.runWithIO`,
36+
`Env.runWithIO`, and `Logger.runWithIO` which are the default handlers for their
37+
respective effects.
38+
39+
For example, `Clock.runWithIO` is declared as:
40+
41+
```flix
42+
@DefaultHandler
43+
pub def runWithIO(f: Unit -> a \ ef): a \ (ef - Clock) + IO = ...
44+
```
45+
46+
A default handler is declared using the `@DefaultHandler` annotation. Each
47+
effect may have at most one default handler, and it must reside in the companion
48+
module of that effect.
49+
50+
A default handler must have a signature of the form:
51+
52+
```flix
53+
def runWithIO(f: Unit -> a \ ef): a \ (ef - E) + IO
54+
```
55+
where `E` is the name of the effect.
56+
57+
We can use effects with default handlers in tests. For example:
58+
59+
```flix
60+
@Test
61+
def myTest01(): Unit \ {Assert, Logger} =
62+
Logger.info("Running test!");
63+
Assert.assertEq(expected = 42, 42)
64+
```

0 commit comments

Comments
 (0)