An exception is a language-dependent mechanism that abruptly terminates ordinary control flow after an unexpected condition. It can be caught; otherwise, termination can prevent continued corruption or security breaches. Exceptions are usually implicit and domain-agnostic, unlike errors: expected, explicit, domain-related states that should be represented and handled deliberately. section 13.1.1 section 13.3
Treating every failure as an exception hides a system’s supported outcomes. A native library exception can also leak implementation details into business logic, coupling it to external libraries. Prefer explicit, value-based errors for anticipated failures, and convert representations at boundaries between error domains. section 13.1.1 section 13.3
When an external operation throws a synchronous exception, an interpreter can choose among three boundary strategies:
- Catch it and convert it into a domain error value in the language’s smart constructor, keeping native results internal. section 13.1.3
- Catch and convert it in the interpreter, so the language exposes only the domain-level result. section 13.1.3
- Drop the result and silence the exception when callers need no success guarantee; document that the operation may do nothing. section 13.1.3
Figure 13.3 Three options for dealing with native exceptions
Compare where a native exception is caught, converted into a value, or deliberately discarded as control crosses an interpreter boundary. section 13.1.3
File-system write as an explicit result
A filesystem interpreter wraps writeFile with try, turning an IOException into Either. The surrounding FileSystem language then maps that native result to FSResult, such as FileNotFound or OtherError, before business logic sees it. Moving the conversion into the interpreter instead keeps NativeResult out of the language interface. section 13.1.3
Free monadic scenarios do not automatically retain control after an interpreter throws: evaluation stops and the exception reaches the outer IO entry point. To handle one within the scenario, make throwing and protected execution explicit language operations, such as throwException and runSafely; the interpreter implements them with throwIO and try. section 13.1.4
Database initialization in a meteor application
A meteor query first initializes SQLite. The ordinary path branches on an explicit initialization result and logs then quits on failure. An unsafe variant converts that error into AppException; wrapping it with runSafely restores an Either result so scenario logic can branch again. section 13.1.4
Exceptions remain possible in a free-monad design, but prohibiting implicit exceptions is presented as the stronger default. Divide error handling by architectural and error-domain boundaries, then make conversions explicit where those domains meet. section 13.3 section 13.1
























