Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/common-problems.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ eff Emit[t] {
def emit(x: t): Unit
}

def f(): Unit \ Emit[Int32] + Emit[String] =
def f(): Unit \ { Emit[Int32], Emit[String] } =
Emit.emit(42);
Emit.emit("Hello")
```
Expand All @@ -138,9 +138,9 @@ The Flix compiler reports:

>> Mismatched type arguments for effect 'Emit': 'Int32' and 'String'.

5 | def f(): Unit \ Emit[Int32] + Emit[String] =
^^^^^^^^^^^^
mismatched effect type argument.
5 | def f(): Unit \ { Emit[Int32], Emit[String] } =
^^^^^^^^^^^^
mismatched effect type argument.

The effect 'Emit' is used with different types for its 1st type parameter 't'.

Expand Down
10 changes: 5 additions & 5 deletions src/concurrency.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Here is an example of sending and receiving a message
over a channel:

```flix
def main(): Int32 \ {Chan, NonDet, IO} = region rc {
def main(): Int32 \ { Chan, NonDet, IO } = region rc {
let (tx, rx) = Channel.unbuffered();
spawn Channel.send(42, tx) @ rc;
Channel.recv(rx)
Expand Down Expand Up @@ -89,7 +89,7 @@ def meow(tx: Sender[String]): Unit \ Chan =
def woof(tx: Sender[String]): Unit \ Chan =
Channel.send("Woof!", tx)

def main(): Unit \ {Chan, NonDet, IO} = region rc {
def main(): Unit \ { Chan, NonDet, IO } = region rc {
let (tx1, rx1) = Channel.buffered(1);
let (tx2, rx2) = Channel.buffered(1);
spawn meow(tx1) @ rc;
Expand All @@ -115,7 +115,7 @@ We can achieve this with a _default case_ as shown
below:

```flix
def main(): String \ {Chan, NonDet} = region rc {
def main(): String \ { Chan, NonDet } = region rc {
let (_, rx1) = Channel.buffered(1);
let (_, rx2) = Channel.buffered(1);
select {
Expand Down Expand Up @@ -146,12 +146,12 @@ a channel, but the `select` expression relies on
giving up:

```flix
def slow(tx: Sender[String]): Unit \ {Chan, NonDet, IO} =
def slow(tx: Sender[String]): Unit \ { Chan, NonDet, IO } =
let delay = Channel.timeout(60, Time.TimeUnit.Seconds);
Channel.recv(delay);
Channel.send("I am very slow", tx)

def main(): Unit \ {Chan, NonDet, IO} = region rc {
def main(): Unit \ { Chan, NonDet, IO } = region rc {
let (tx, rx) = Channel.buffered(1);
spawn slow(tx) @ rc;
let timeout = Channel.timeout(5, Time.TimeUnit.Seconds);
Expand Down
6 changes: 3 additions & 3 deletions src/default-handlers.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ For example, we can write:
use Sys.Env
use Time.Clock

def main(): Unit \ {Clock, Env, Logger} =
def main(): Unit \ { Clock, Env, Logger } =
let ts = Clock.currentTime(TimeUnit.Milliseconds);
let os = Env.getOsName();
Logger.info("UNIX Timestamp: ${ts}");
Expand Down Expand Up @@ -64,7 +64,7 @@ We can use effects with default handlers in tests. For example:

```flix
@Test
def myTest01(): Unit \ {Assert, Logger} =
def myTest01(): Unit \ { Assert, Logger } =
Logger.info("Running test!");
Assert.assertEq(expected = 42, 42)
```
Expand All @@ -89,7 +89,7 @@ mod Emit {
}
}

def main(): Unit \ {Emit[Int32], IO} =
def main(): Unit \ { Emit[Int32], IO } =
Emit.emit(42);
println("Done")
```
Expand Down
10 changes: 5 additions & 5 deletions src/effect-oriented-programming.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.{Random => JRandom}

def getSecretNumber(): Int32 \ {NonDet, IO} =
def getSecretNumber(): Int32 \ { NonDet, IO } =
let rnd = new JRandom();
rnd.nextInt()

Expand Down Expand Up @@ -61,7 +61,7 @@ def gameLoop(secret: Int32): Unit \ IO = {
}
}

def main(): Unit \ {NonDet, IO} =
def main(): Unit \ { NonDet, IO } =
let secret = getSecretNumber();
gameLoop(secret)
```
Expand Down Expand Up @@ -100,12 +100,12 @@ eff Terminal {
def println(s: String): Unit
}

def readAndParseGuess(): Result[String, Int32] \ {Guess} =
def readAndParseGuess(): Result[String, Int32] \ Guess =
forM(g <- Guess.readGuess();
n <- Int32.parse(10, g)
) yield n

def gameLoop(secret: Int32): Unit \ {Guess, Terminal} = {
def gameLoop(secret: Int32): Unit \ { Guess, Terminal } = {
Terminal.println("Enter a guess:");
match readAndParseGuess() {
case Result.Ok(g) =>
Expand All @@ -121,7 +121,7 @@ def gameLoop(secret: Int32): Unit \ {Guess, Terminal} = {
}
}

def main(): Unit \ {NonDet, IO} =
def main(): Unit \ { NonDet, IO } =
run {
let secret = Secret.getSecret();
gameLoop(secret)
Expand Down
40 changes: 20 additions & 20 deletions src/effect-polymorphism.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
In Flix, we can express that a function is pure (i.e. has no side-effects):

```flix
def inc(x: Int32): Int32 \ { } = x + 1
// ^^^ empty effect set
def inc(x: Int32): Int32 \ {} = x + 1
// ^^ empty effect set
```

The `inc` function is _pure_ because its effect set is empty. When a function is
Expand All @@ -26,8 +26,8 @@ def inc(x: Int32): Int32 = x + 1
In Flix, we can express that a function has a single effect:

```flix
def incAndPrint(x: Int32): Int32 \ {IO} =
let result = x + 1; // ^^^^ singleton effect set
def incAndPrint(x: Int32): Int32 \ IO =
let result = x + 1; // ^^ singleton effect set
println(result);
result
```
Expand All @@ -38,8 +38,8 @@ Here the `incAndPrint` function has the primitive `IO` effect.
We can also express that a function has multiple effects:

```flix
def copyFile(src: File, dst: File): Unit \ {FsRead, FsWrite, IO} = ...
// ^^^^^^^^^^^^^^^^^^^^ multiple effects
def copyFile(src: File, dst: File): Unit \ { FsRead, FsWrite, IO } = ...
// ^^^^^^^^^^^^^^^^^^^^^^^ multiple effects
```

Here the `copyFile` function has three primitive effects: `FsRead`, `FsWrite`,
Expand All @@ -48,8 +48,8 @@ and `IO`.
In Flix, we can express a function that has a heap effect:

```flix
def nth(i: Int32, a: Array[t, r]): Option[a] \ {r} = ....
// ^^^ heap effect
def nth(i: Int32, a: Array[t, r]): Option[a] \ r = ....
// ^ heap effect
```

Here the `nth` function has a heap effect in the region `r`.
Expand All @@ -59,8 +59,8 @@ We can also write functions that mix different effects:
```flix
use Time.Clock

def strange(a: Array[t, r]): Unit \ {r, Clock, Http, IO}
// ^^^^^^^^^^^^^^^^^^^ a mixture of effects
def strange(a: Array[t, r]): Unit \ r + { Clock, Http, IO }
// ^^^^^^^^^^^^^^^^^^^^^^^ a mixture of effects
```

This function has a heap effect `r` and three effects: `Clock`, `Http`, and `IO`.
Expand All @@ -72,8 +72,8 @@ When we write higher-order functions, we must think carefully about their effect
For example, we can write a higher-order function `Set.exists`:

```flix
def exists(f: a -> Bool \ { }, s: Set[a]): Bool = ...
^^^
def exists(f: a -> Bool \ {}, s: Set[a]): Bool = ...
^^
```

Here the `exists` function enforces the predicate function `f` to be pure. Why
Expand All @@ -100,8 +100,8 @@ pure (i.e. has no effects) then the call to `map` will be pure. If `f` has the


```flix
List.map(x -> x + 1, l) // has the { } effect (i.e., is pure)
List.map(x -> {println(x); x + 1}, l) // has the { IO } effect
List.map(x -> x + 1, l) // has the {} effect (i.e., is pure)
List.map(x -> {println(x); x + 1}, l) // has the IO effect
```

A higher-order function that takes multiple function arguments may combine their
Expand Down Expand Up @@ -171,9 +171,9 @@ For example, if we write:
if (???) { x -> x + 1 } else { x -> {println(x); x + 1}}
```

The first branch should have type `Int32 -> Int32 \ { }` (i.e. it is pure)
whereas the second branch has type `Int32 -> Int32 \ { IO }`. Without
sub-effecting these two types are incompatible because `{ } != { IO }`. However,
The first branch should have type `Int32 -> Int32 \ {}` (i.e. it is pure)
whereas the second branch has type `Int32 -> Int32 \ IO`. Without
sub-effecting these two types are incompatible because `{} != IO`. However,
because of sub-effecting, Flix gives the first branch the type `Int32 -> Int32 \
ef` for some fresh effect variable `ef`. This allows type inference to _widen_
the effect of the first branch to `IO`. Hence the compiler is able to type check
Expand Down Expand Up @@ -201,7 +201,7 @@ For example, we can define the trait:

```flix
trait Foo[t] {
def f(x: t): Bool \ { IO }
def f(x: t): Bool \ IO
}
```

Expand All @@ -214,8 +214,8 @@ instance Foo[Int32] {
```

The declared effect of `f` is `IO`, but here the implementation of `f` is pure
(i.e., it has the empty effect set `{ }`). The program still type checks because
`{ }` can be widened to `IO`.
(i.e., it has the empty effect set `{}`). The program still type checks because
`{}` can be widened to `IO`.

Flix, however, does not allow sub-effecting for top-level functions.

Expand Down
6 changes: 3 additions & 3 deletions src/effects-and-handlers.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ eff HourOfDay {
def getCurrentHour(): Int32
}

def greeting(): String \ {HourOfDay} =
def greeting(): String \ HourOfDay =
let h = HourOfDay.getCurrentHour();
if (h <= 12)
"Good morning"
Expand Down Expand Up @@ -136,7 +136,7 @@ eff Say {
def say(s: String): Unit
}

def greeting(): Unit \ {Ask, Say} =
def greeting(): Unit \ { Ask, Say } =
let name = Ask.ask();
Say.say("Hello Mr. ${name}")

Expand Down Expand Up @@ -174,7 +174,7 @@ eff Exc {
def raise(m: String): Void
}

def drunkFlip(): String \ {Amb, Exc} = {
def drunkFlip(): String \ { Amb, Exc } = {
if (Amb.flip()) {
let heads = Amb.flip();
if (heads) "heads" else "tails"
Expand Down
6 changes: 3 additions & 3 deletions src/for-llms.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,11 +260,11 @@ use `run`/`with handler` blocks instead.
&#x274C; **Incorrect (manual CPS with nested callbacks):**

```
def handleSleep(f: Unit -> a \ { Sleep, ef }): a \ ef + IO = ...
def handleSleep(f: Unit -> a \ ef + Sleep): a \ ef + IO = ...

def withLogging(f: Unit -> a \ { Sleep, ef }): a \ ef + { Sleep, Logger } = ...
def withLogging(f: Unit -> a \ ef + Sleep): a \ ef + { Sleep, Logger } = ...

def withJitter(factor: Float64, f: Unit -> a \ { Sleep, ef }): a \ ef + { Sleep, Random } = ...
def withJitter(factor: Float64, f: Unit -> a \ ef + Sleep): a \ ef + { Sleep, Random } = ...

def main(): Unit \ { Logger, Random, Sleep, IO } =
handleSleep(() ->
Expand Down
8 changes: 4 additions & 4 deletions src/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ eff MyTime {
def getCurrentHour(): Int32
}

def sayGreeting(name: String): Unit \ {MyPrint, MyTime} = {
def sayGreeting(name: String): Unit \ { MyPrint, MyTime } = {
let hour = MyTime.getCurrentHour();
if (hour < 12)
MyPrint.println("Good morning, ${name}")
Expand Down Expand Up @@ -194,18 +194,18 @@ def sendAll(l: List[Int32], tx: Sender[Int32]): Unit \ Chan =

/// A function that receives n elements
/// and collects them into a list.
def recvN(n: Int32, rx: Receiver[Int32]): List[Int32] \ {Chan, NonDet} =
def recvN(n: Int32, rx: Receiver[Int32]): List[Int32] \ { Chan, NonDet } =
match n {
case 0 => Nil
case _ => Channel.recv(rx) :: recvN(n - 1, rx)
}

/// A function that calls receive and sends the result on d.
def wait(rx: Receiver[Int32], n: Int32, tx: Sender[List[Int32]]): Unit \ {Chan, NonDet} =
def wait(rx: Receiver[Int32], n: Int32, tx: Sender[List[Int32]]): Unit \ { Chan, NonDet } =
Channel.send(recvN(n, rx), tx)

/// Spawn a process for send and wait, and print the result.
def main(): Unit \ {Chan, NonDet, IO} = region rc {
def main(): Unit \ { Chan, NonDet, IO } = region rc {
let l = 1 :: 2 :: 3 :: Nil;
let (tx1, rx1) = Channel.buffered(100);
let (tx2, rx2) = Channel.buffered(100);
Expand Down
10 changes: 5 additions & 5 deletions src/java-collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ The following functions _convert_ Flix collections to Java collections:
///
/// Lists
///
def toList(ma: m[a]): JList[a] \ IO + Aef[m] with Foldable[m]
def toArrayList(ma: m[a]): JArrayList[a] \ IO + Aef[m] with Foldable[m]
def toLinkedList(ma: m[a]): JLinkedList[a] \ IO + Aef[m] with Foldable[m]
def toList(ma: m[a]): JList[a] \ { Aef[m], IO } with Foldable[m]
def toArrayList(ma: m[a]): JArrayList[a] \ { Aef[m], IO } with Foldable[m]
def toLinkedList(ma: m[a]): JLinkedList[a] \ { Aef[m], IO } with Foldable[m]

///
/// Sets
///
def toSet(ma: m[a]): JSet[a] \ IO + Aef[m] with Order[a], Foldable[m]
def toTreeSet(ma: m[a]): JTreeSet[a] \ IO + Aef[m] with Order[a], Foldable[m]
def toSet(ma: m[a]): JSet[a] \ { Aef[m], IO } with Order[a], Foldable[m]
def toTreeSet(ma: m[a]): JTreeSet[a] \ { Aef[m], IO } with Order[a], Foldable[m]

///
/// Maps
Expand Down
2 changes: 1 addition & 1 deletion src/logger.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ mod Logger {
The convenience functions accept any value that implements `Formattable`:

```flix
def main(): Unit \ { Logger } =
def main(): Unit \ Logger =
Logger.info("Application started");
Logger.debug("Loading configuration...");
Logger.warn("Cache size exceeds threshold");
Expand Down
4 changes: 2 additions & 2 deletions src/main.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ For example, main can use the `Env` and `Exit` effects:
use Sys.Env
use Sys.Exit

def main(): Unit \ {Env, Exit} =
def main(): Unit \ { Env, Exit } =
let args = Env.getArgs();
match List.head(args) {
case None =>
Expand All @@ -44,7 +44,7 @@ The command line arguments passed to the program can be accessed by calling
```flix
use Sys.Env

def main(): Unit \ {Env, IO} =
def main(): Unit \ { Env, IO } =
let args = Env.getArgs();
println("Arguments: ${args}")
```
Expand Down
2 changes: 1 addition & 1 deletion src/mutable-collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def sweetFruits(rc: Region[r]): MutList[String, r] \ r =
MutList.push("Pear") !>
MutList.push("Mango")

def printFruits(fruits: MutList[String, r]): Unit \ {r, IO} =
def printFruits(fruits: MutList[String, r]): Unit \ r + IO =
MutList.forEach(println, fruits)
```

Expand Down
8 changes: 4 additions & 4 deletions src/polymorphic-effects.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ must be used with the same type arguments everywhere.
For example, if we write:

```flix
def f(): Unit \ Emit[Int32] + Emit[String] =
def f(): Unit \ { Emit[Int32], Emit[String] } =
Emit.emit(42);
Emit.emit("Hello")
```
Expand All @@ -158,9 +158,9 @@ The Flix compiler emits the error message:

>> Mismatched type arguments for effect 'Emit': 'Int32' and 'String'.

5 | def f(): Unit \ Emit[Int32] + Emit[String] =
^^^^^^^^^^^^
mismatched effect type argument.
5 | def f(): Unit \ { Emit[Int32], Emit[String] } =
^^^^^^^^^^^^
mismatched effect type argument.

The effect 'Emit' is used with different types for its 1st type parameter 't'.

Expand Down
Loading
Loading