File I/O
Reading, writing, and deleting files using the File effect. Errors are
represented as an ADT (FileError), not strings, so you can match on specific
failure cases.
import Std.File (File, FileError, fs)
fun process : Unit -> Unit needs {File}
process () = {
let result = File.write! "test_output.txt" "hello from saga!"
case result {
Ok () -> ()
Err _ -> dbg "write failed"
}
let result = File.read! "test_output.txt"
case result {
Ok content -> dbg content
Err e -> case e {
File.NotFound -> dbg "file not found"
File.PermissionDenied -> dbg "permission denied"
_ -> dbg "other error"
}
}
let _ = File.delete! "test_output.txt"
dbg $"file exists after delete?: {File.exists! "test_output.txt"}"
let missing = File.read! "nonexistent.txt"
case missing {
Ok _ -> dbg "unexpected"
Err File.NotFound -> dbg "correctly got NotFound"
Err e -> dbg $"wrong error: {debug e}"
}
}
main () = process () with fsOutput:
hello from saga!
file exists after delete?: False
correctly got NotFound
The fs handler connects the File effect to the real filesystem. In tests,
you could provide a handler that operates on an in-memory map instead.