-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path03_effects.affine
More file actions
77 lines (62 loc) · 2.56 KB
/
Copy path03_effects.affine
File metadata and controls
77 lines (62 loc) · 2.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// SPDX-License-Identifier: MPL-2.0
// Warmup 03: Algebraic effects
//
// Effects are AffineScript's unified model for anything "impure":
// I/O, state, exceptions, async, randomness, etc.
//
// The key idea: effects are declared in return types, not thrown sideways.
// The compiler knows every effect a function can perform.
//
// Run: affinescript check 03_effects.affine
// ── Declaring an effect ───────────────────────────────────────────────────────
effect IO {
fn print(s: String);
fn println(s: String);
fn read_line() -> String;
}
// ── Using an effect ───────────────────────────────────────────────────────────
//
// The `/ EffectName` in the return type declares which effects are used.
// No `perform` keyword — just call the operation directly (ADR-008).
fn greet(name: ref String) -> () / IO {
println("Hello, " ++ name ++ "!")
}
// Multiple effects are composed with `+`:
effect Exn[E] {
fn throw(err: E) -> Never;
}
type IOError = { message: String }
fn read_line_safe() -> Result[String, IOError] / IO + Exn[IOError] {
let line = IO.read_line();
if line == "" {
Exn.throw({ message: "empty input" })
} else {
Ok(line)
}
}
// ── Effect polymorphism ───────────────────────────────────────────────────────
//
// Functions can be polymorphic over effects — they propagate whatever effects
// their argument functions use.
fn map_list[A, B, ..e](
xs: ref Array[A],
f: (ref A) -> B / e
) -> Array[B] / e {
// Implementation would map f over xs
[]
}
// ── Parameterised effects ─────────────────────────────────────────────────────
effect State[S] {
fn get() -> S;
fn put(s: S) -> ();
}
effect Async {
fn await[T](promise: Promise[T]) -> T;
fn spawn[T](f: () -> T) -> Promise[T];
}
// ── Exercise 1: write a function that reads two lines and returns ──────────────
// a tuple of them. What effects does it declare?
// fn read_pair() -> (String, String) / ??? { ... }
// ── Exercise 2: write a counter using State[Int] that increments by n ─────────
// and returns the new value.
// fn increment(n: Int) -> Int / State[Int] { ... }