Skip to content

Commit ee900d0

Browse files
authored
Forward reference computation section (#1044)
Resolves effekt-lang/effekt-website#116
1 parent 3cacf59 commit ee900d0

File tree

3 files changed

+23
-9
lines changed

3 files changed

+23
-9
lines changed

examples/tour/computation.effekt.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
---
2-
title: Computation
2+
title: Computations
33
permalink: tour/computation
44
---
55

6-
# Computation
6+
# Computations
77

8-
## Values vs. Computation
8+
## Values vs. Computations
99

10-
Following Paul Levy's [Call-By-Push-Value](https://www.cs.bham.ac.uk/~pbl/papers/thesisqmwphd.pdf), Effekt distinguishes between **values** (such as `42`, `true`, or instances of datatypes) and **computation**.
10+
Following Paul Levy's [Call-By-Push-Value](https://www.cs.bham.ac.uk/~pbl/papers/thesisqmwphd.pdf), Effekt distinguishes between **values** (such as `42`, `true`, or instances of datatypes) and **computations**.
1111

12-
Examples of "computation" in Effekt are:
12+
Examples of "computations" in Effekt are:
1313
- blocks (this is what we call functions),
1414
- instances of interfaces (also known as "objects"), and
1515
- regions
1616

17-
Functions (and all other computation types) are _second-class_ in Effekt. To make this difference explicit, we pass values in parentheses (e.g. `f(42)`) and computation in braces (e.g. `f { x => println(x) }`).
17+
Functions (and all other computation types) are _second-class_ in Effekt. To make this difference explicit, we pass values in parentheses (e.g. `f(42)`) and computations in braces (e.g. `f { x => println(x) }`).
1818

1919
```
2020
def myMap[A, B](xs: List[A]) { f: A => B }: List[B] =
@@ -58,7 +58,7 @@ The effects used in the passed block thus need to be handled exactly where the b
5858

5959
## Comparison
6060

61-
| | Values (First-class) | Computation (Second-class) |
61+
| | Values (First-class) | Computations (Second-class) |
6262
|---|:---|---:|
6363
| Term-level | `42`, `"hello"`, `true`, `Cons(1, Nil)`, `box { [A](x: A) => x }` ... | `{ [A](x: A) => x }`, `new Exception`, `region r`, `unbox exc` |
6464
| | Literals, instances of datatypes and boxed computations | Blocks, objects and regions |

examples/tour/effect-handlers.effekt.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ genFibs(15).foreach { x => println(x) }
111111
## Singleton operation
112112

113113
Often, we want to declare an interface that is entirely defined by just one operation (like a "single-abstract-method" in Java). In this case, you can declare it as a singleton operation:
114+
114115
```
115116
effect tell(): Int
116117
```
@@ -127,6 +128,11 @@ def tellTime[A] { prog: () => A / tell }: A =
127128
}
128129
```
129130

131+
Here, `prog` is expected to be passed a computation (block) and not as a value.
132+
You can read more about their distinction in the section about [computations](computation).
133+
134+
Using the function `tellTime` that _handles_ the effect `tell` of `prog`, we can write the following program for measuring the execution time for computing the first 1500 Fibonacci Numbers:
135+
130136
```effekt:repl
131137
tellTime {
132138
val start = do tell()
@@ -137,8 +143,10 @@ tellTime {
137143
```
138144

139145
## `with` handler
146+
140147
We can decompose `genFibs` into a more general helper function `collect` that collects the
141148
yielded values by abstracting over the generating program:
149+
142150
```
143151
def collect[A](n: Int) { prog: () => Unit / Yield[A] }: List[A] = {
144152
var yielded: List[A] = []
@@ -156,7 +164,9 @@ def collect[A](n: Int) { prog: () => Unit / Yield[A] }: List[A] = {
156164
yielded
157165
}
158166
```
167+
159168
Let us define another handler for `Yield` to filter values:
169+
160170
```
161171
def filter[A] { keep: A => Bool } { prog: () => Unit / Yield[A] }: Unit / Yield[A] =
162172
try prog()
@@ -166,6 +176,7 @@ def filter[A] { keep: A => Bool } { prog: () => Unit / Yield[A] }: Unit / Yield[
166176
```
167177

168178
We can avoid the nesting of higher-order function calls like `collect[Int](limit) { filter { x => x.mod(2) == 0 } { fib() } }` and write:
179+
169180
```
170181
def evenFibs(limit: Int): List[Int] = {
171182
with collect(limit)
@@ -174,8 +185,6 @@ def evenFibs(limit: Int): List[Int] = {
174185
}
175186
```
176187

177-
178-
179188
```effekt:repl
180189
evenFibs(15).foreach { x => println(x) }
181190
```

examples/tour/functions.effekt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Perhaps unusual, you can also call `fib` using Effekt's implementation of [Unifo
2828
```effekt:repl
2929
5.fib()
3030
```
31+
3132
Here, the receiver (before the `.`) is simply passed as the first argument to the function `fib`. If there are no additional arguments, you can also omit the parenthesis:
3233

3334
```effekt:repl
@@ -68,3 +69,7 @@ def odd(n: Int): Bool = if (n <= 0) false else even(n - 1)
6869
```effekt:repl
6970
7.even
7071
```
72+
73+
Of course, it is also possible to implement higher-order functions in Effekt.
74+
However, we distinguish between first-class values and second-class computations.
75+
You can read more about this in the section about [computations](computation).

0 commit comments

Comments
 (0)