I am using the custom let bindings introduced in Ocaml 4.08 to implement a custom monad. Here is a snippet of how this is implemented:
type 'a t = state -> (state * 'a)
let return a = fun s -> (s, a)
module Syntax = struct
(* For ppx_let *)
module Let_syntax = struct
let bind m ~f = fun sin ->
let sout, res = m sin in
f res sout
let return = return
let map m ~f = fun sin ->
let sout, res = m sin in
(sout, f res)
let both m1 m2 = fun sin ->
let s1, res1 = m1 sin in
let s2, res2 = m2 s1 in
(s2, (res1, res2))
end
open Let_syntax
let (let+) (m: state -> state * 'a) (f: 'a -> 'b) : (state -> state * 'b) = map m ~f
let (and+) = both
let (let* ) (m: state -> state * 'a) (f: 'a -> state -> state * 'b) : (state -> state * 'b) = bind m ~f
let (and* ) = both
end
These bindings make my code much more readable and streamlined. The issue is that when exceptions are raised, using Backtrace.Exn.most_recent ()
to print the backtrace does not yield useful backtraces. Instead of the actual functions being called, the backtrace is full of references to Rewriter.Let_syntax.map
and Rewriter.Let_syntax.bind
, for example:
Raised at Util__Error.fail in file "lib/util/error.ml", line 10, characters 24-51
Called from Ast__Rewriter.resolve_and_find in file "lib/ast/rewriter.ml", line 811, characters 52-95
Called from Ast__Rewriter.Syntax.Let_syntax.map in file "lib/ast/rewriter.ml", line 26, characters 13-18
Called from Ast__Rewriter.Syntax.Let_syntax.map in file "lib/ast/rewriter.ml", line 25, characters 22-27
Called from Ast__Rewriter.Syntax.Let_syntax.map in file "lib/ast/rewriter.ml", line 25, characters 22-27
Called from Ast__Rewriter.Syntax.Let_syntax.bind in file "lib/ast/rewriter.ml", line 19, characters 22-27
This makes the backtrace essentially useless. In the definitions of bind
and map
, if an exception is raised during the computation of m
, the corresponding functions are not appearing in the backtrace. Why might that be the case?
What can I do to ensure that the information about these functions is preserved in the backtrace? For example, would it be possible to modify the bind
and map
functions to add more information to the backtrace when exceptions occur? I don’t understand the backtrace enough to figure out how to do something like that.