Skip to content

Instantly share code, notes, and snippets.

@keleshev
Created December 8, 2020 19:42
Show Gist options
  • Save keleshev/c8d6d8adac646839fdc6664d44cb91c6 to your computer and use it in GitHub Desktop.
Save keleshev/c8d6d8adac646839fdc6664d44cb91c6 to your computer and use it in GitHub Desktop.
(* https://keleshev.com/composable-error-handling-in-ocaml *)
open Printf
let (>>=) = Result.bind
let (let*) = Result.bind
module Exceptions_example (X: sig
type tree
module Parser : sig
exception SyntaxError of int
exception GrammarError of {line: int; message: string}
(** Can raise [Parser.SyntaxError] or [Parser.GrammarError] *)
val parse : string -> tree
end
module Validation : sig
exception LengthError of int
exception HeightError of int
(** Can raise [Validation.LengthError] or [Validation.HeightError] *)
val perform : tree -> tree
end
module Display : sig
exception Error of string
(** Can raise [Display.Error] *)
val render : tree -> string
end
end) = struct
open X
let main source =
let tree = Parser.parse source in
let tree = Validation.perform tree in
Display.render tree
open Printf
let handle_errors source =
try
printf "%s" (main source)
with
| Parser.SyntaxError line ->
eprintf "Syntax error at line %d" line
| Parser.(GrammarError {line; message}) ->
eprintf "Grammar error at line %d: %s" line message
| Validation.LengthError length ->
eprintf "Validation error: length %d is out of bounds" length
| Validation.HeightError height ->
eprintf "Validation error: height %d is out of bounds" height
| Display.Error message ->
eprintf "Display error: %s" message
end
module Result_with_strings_example (X: sig
type tree
module Parser : sig
val parse : string -> (tree, string) result
end
module Validation : sig
val perform : tree -> (tree, string) result
end
module Display : sig
val render : tree -> (string, string) result
end
end) = struct
open X
let main source =
match Parser.parse source with
| Error message ->
eprintf "Parser error: %s" message
| Ok tree ->
match Validation.perform tree with
| Error message ->
eprintf "Validation error: %s" message
| Ok tree ->
match Display.render tree with
| Error message ->
eprintf "Display error: %s" message
| Ok output ->
printf "%s" output
(* * *)
let main source =
Result.bind (Parser.parse source) (fun tree ->
Result.bind (Validation.perform tree) (fun tree ->
Display.render tree))
let main2 source =
Parser.parse source >>= fun tree ->
Validation.perform tree >>= fun tree ->
Display.render tree
let main3 source =
let* tree = Parser.parse source in
let* tree = Validation.perform tree in
Display.render tree
(* * *)
let handle_errors source =
match main source with
| Error message -> eprintf "Error: %s" message
| Ok output -> printf "%s" output
end
module Result_with_variant_example (X: sig
type tree
module Parser : sig
type error =
| SyntaxError of int
| GrammarError of {line: int; message: string}
val parse : string -> (tree, error) result
end
module Validation : sig
type error =
| LengthError of int
| HeightError of int
val perform : tree -> (tree, error) result
end
module Display : sig
val render : tree -> (string, string) result
end
end) = struct
open X
let main source =
match Parser.parse source with
| Error Parser.(SyntaxError line) ->
eprintf "Syntax error at line %d" line
| Error Parser.(GrammarError {line; message}) ->
eprintf "Grammar error at line %d: %s" line message
| Ok tree ->
match Validation.perform tree with
| Error Parser.(LengthError length) ->
eprintf "Validation error: Length %d is out of bounds" length
| Error Parser.(HeightError height) ->
eprintf "Validation error: Height %d is out of bounds" height
| Ok tree ->
match Display.render tree with
| Error message -> eprintf "Display error: %s" message
| Ok output -> printf "%s" output
end
module Result_with_polymorhpic_variants_example (X: sig
type tree
module Parser : sig
type error = [
| `ParserSyntaxError of int
| `ParserGrammarError of int * string
]
val parse : string -> (tree, [> error]) result
end
module Validation : sig
type error = [
| `ValidationLengthError of int
| `ValidationHeightError of int
]
val perform : tree -> (tree, [> error]) result
end
module Display : sig
type error = [
| `DisplayError of string
]
val render : tree -> (string, [> error]) result
end
end): sig
open X
val parse_and_validate : string -> (tree, [>
| `ParserSyntaxError of int
| `ParserGrammarError of int * string
| `ValidationLengthError of int
| `ValidationHeightError of int
]) result
val main : string -> (string, [>
| `ParserSyntaxError of int
| `ParserGrammarError of int * string
| `ValidationLengthError of int
| `ValidationHeightError of int
| `DisplayError of string
]) result
end = struct
open X
let parse_and_validate source =
let* tree = Parser.parse source in
Validation.perform tree
let main source =
let* tree = Parser.parse source in
let* tree = Validation.perform tree in
Display.render tree
let handle_errors source =
match main source with
| Ok output ->
printf "%s" output
| Error (`ParserSyntaxError line) ->
eprintf "Syntax error at line %d" line
| Error (`ParserGrammarError (line, message)) ->
eprintf "Grammar error at line %d: %s" line message
| Error (`ValidationLengthError length) ->
eprintf "Validation error: length %d is out of bounds" length
| Error (`ValidationHeightError height) ->
eprintf "Validation error: height %d is out of bounds" height
| Error (`DisplayError message) ->
eprintf "Display error: %s" message
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment