I both agree and disagree with you on the flexibility on PPXes. I could see two ways to approach your problem.
One of the benefits I find to PPXes is the fact that you have a tiny string regularly reminding you in which monad (or at least which PPX extension, they might not implement monads) you live. This is more annoying when writing, and this requires defining a new PPX for each new monad that you are going to use. This is heavy and (I agree with you here) much less flexible. I do think it makes reading easier because it requires less context to read a function (“what’s the bind
in this context already?”) The first solution I see would then be to define a PPX rewriter for the Lwt_result
monad, say %rlwt
, and then use it in your function:
let seed2 conn : (unit, 'error) result Lwt.t =
let%rlwt () = add_author conn "John" "Doe" in
let%rlwt () = add_author conn "Jane" "Doe" in
let%rlwt () = add_author conn "Robert" "Doe" in
Lwt.return_ok ()
Actually, if you have this PPX, you could also go for:
let seed2 conn : (unit, 'error) result Lwt.t =
add_author conn "John" "Doe";%rlwt
add_author conn "Jane" "Doe";%rlwt
add_author conn "Robert" "Doe"
This is actually something I do in my projects, because I very often rely on the Lwt_result
monad.
Now sometimes we do want to use a monad only locally and it wouldn’t make much sense to define a PPX for that. Something I use in those cases is a PPX that rewrites %m
(or %monad
; maybe that should actually be %bind
) into an unqualified bind
(PPXes only perform syntactic replacements) which then will be whatever you use locally. We lose the naming that I enjoy, but we gain some flexibility. So I would do:
let seed2 conn : (unit, 'error) result Lwt.t =
let bind = Lwt_result.bind in
let%m () = add_author conn "John" "Doe" in
let%m () = add_author conn "Jane" "Doe" in
let%m () = add_author conn "Robert" "Doe" in
Lwt.return_ok ()
At this point, this is just the same as the let*
syntax, except maybe a bit more verbose. However, you don’t get only the let
, of course:
let seed2 conn : (unit, 'error) result Lwt.t =
let bind = Lwt_result.bind in
add_author conn "John" "Doe";%m
add_author conn "Jane" "Doe";%m
add_author conn "Robert" "Doe"
I am not sure I’d recommend one to do those things. I feel it is rather uncommon in the OCaml ecosystem to do that? I like it though, so I stick with PPXes. Because I spend my time redefining PPXes for all kind of things, I’ve tried to make it easy for myself by implementing ppx_monad. In particular, it helps me easily define custom monadic syntaxes, and it provides the %monad
extension. I think I must be the sole user of this, though, so external feedback is most welcome.