Next Steps
We are now ready write our first real program!
We will write a simple variant of the venerable wordcount (wc
) program from
UNIX.
We will use the opportunity to illustrate how to use algebraic effects in Flix.
def wc(file: String): Unit \ {Console, FileReadWithResult} = {
match FileReadWithResult.readLines(file) {
case Ok(lines) =>
let totalLines = List.length(lines);
let totalWords = List.sumWith(numberOfWords, lines);
Console.println("Lines: ${totalLines}, Words: ${totalWords}")
case Err(_) =>
Console.println("Unable to read file: ${file}")
}
}
def numberOfWords(s: String): Int32 =
s |> String.words |> List.length
def main(): Unit \ IO =
run {
wc("Main.flix")
} with Console.runWithIO
with FileReadWithResult.runWithIO
The program works as follows:
We define a wc
function that takes a filename and reads all lines from the
file using the algebraic effect FileReadWithResult
.
If the file is successfully read, we calculate:
- The number of lines using
List.length
. - The number of words by summing the results of applying
numberOfWords
to each line.
The results are printed to the terminal using the Console
algebraic effect.
If the file cannot be read, an error message is printed to the terminal using the same effect.
The wc
function's type and effect signature specifies the {Console, FileReadWithResult}
effect set, indicating these effects are required.
Conceptually, the function is pure except for these effects, which must be
handled by the caller.
The main
function calls wc
with a fixed filename. Since wc
uses the
Console
and FileReadWithResult
effects, we must provide their
implementations. This is achieved using the run-with
construct, where we
specify the default handlers Console.runWithIO
and
FileReadWithResult.runWithIO
.