Exceptions
Use exceptions for unexpected failures and .NET interop. Use Result/Option for expected, domain-level failures.
// Raising
failwith "Something went wrong" // System.Exception
failwithf "Invalid value: %d" 42
invalidArg "age" "Age must be positive" // ArgumentException
invalidOp "Operation not allowed" // InvalidOperationException
nullArg "name" // ArgumentNullException
raise (System.IO.FileNotFoundException "missing.txt")
// Custom F# exceptions
exception InsufficientFunds of needed: decimal * available: decimal
let withdraw balance amount =
if amount > balance then raise (InsufficientFunds (amount, balance))
balance - amount
// Handling
let safeWithdraw balance amount =
try
Ok (withdraw balance amount)
with
| InsufficientFunds (needed, available) -> Error $"Need {needed - available} more"
| :? System.ArgumentException as ex -> Error ex.Message
| ex -> Error $"Unexpected: {ex.Message}"
// try/finally and use (IDisposable)
let readFirstLine path =
use reader = new System.IO.StreamReader(path: string) // disposed at the end of scope
reader.ReadLine()
try
printfn "work"
finally
printfn "cleanup"
// reraise() preserves the stack trace
…