Unless you specifically try to obfuscate your code, writing monadic code without do-notation is pretty easy, e.g., if we will remove excessive1 parentheses from your example it will be already pretty readable,
let v0 =
Ok "one" >>= fun a ->
Ok "two" >>= fun c ->
print_endline a;
print_endline c;
Ok c
And if we will use let-binding operators, e.g., using the monads [1,2] library (also a shameless plug), then we can write it even more concise,
open Monads.Std
open Monad.Result.Error.Syntax
open Monad.Result.Error.Let
let v1 =
let+ a = Ok "one" and+ b = Ok "two" in
print_endline a;
print_endline b;
b
1) OCaml denotes the application operation (both an application of a function to its argument and an application a constructor to its argument) by juxtaposition, e.g., sin x
(not sin(x)
), or Ok 42
(not Ok (42)
), moreover the application operator has higher precedence (binds tighter) than infix operators, so you can write sin x > cos x
. The lambda operator, fun <var> -> <expr>
chains nicely with monadic operators, e.g.,
x >>= (fun x -> y >>= (fun y -> x + y))
is the same as
x >>= fun x -> y >>= fun y -> x + y
or, more often it is written as
x >>= fun x ->
y >>= fun y ->
x + y
as a tribute to the let-legacy of the lambda (abstraction) operator, cf.,
let* x = x in
let* y = y in
x + y
and latest versions of OCaml even allow you to pun the right-hand side, e.g.,
let* x in
let* y in
x + y
or even
let* x and* y in
x + y