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
numberOfWordsto 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.