Skip to content

2e1a. Thoughts on IO and errors

After deciding to drop the event-based model for the CLI tool of NeoHaskell as per 2e1. Scripting in NeoHaskell, I started working on a regular scripting tool using IO. Rapidly, I found myself writing code like the following:

handleCommand :: NeoCommand -> IO ()
handleCommand command =
case command of
Build flags -> do
let readOpts = File.ReadOptions {path = flags.projectFile}
configTxt <- File.readTextHandler readOpts
case configTxt of
Err err -> toText err |> print
Ok txt -> do
case Json.decodeText txt of
Err err -> print err
Ok config -> handleBuild config

Error handling gets nested quickly. Perhaps introducing a Task effect for this kind of things is not that bad of an idea.

Some questions arise:

  • Maybe Tasks could be a monad?
  • Maybe even Actions shouldn’t be serializable?
  • Can we pack error handling and composability into a monoidal structure without sacrificing serializability?