>>= and >>| parse differently?

26 views
Skip to first unread message

Evgeny Roubinchtein

unread,
Jan 24, 2018, 6:42:25 PM1/24/18
to ocaml...@googlegroups.com
I would expect to be able to mechanically substitute ">>= fun x -> Result.return y" with ">>| fun x -> y" in a program, however:

utop # open Core;;

utop # open Result;;

utop # return 1 >>| fun r -> r;;
- : (int, 'a) result = Ok 1

utop # return 1 >>| fun r -> 2 >>| fun r' -> (r, r');;
Error: This expression has type int but an expression was expected of type
         ('a, 'b) result (* the "2" in "fun r -> 2" is underlined *)

utop # return 1 >>= fun r -> return 2 >>| fun r' -> (r, r');;
- : (int * int, 'a) result = Ok (1, 2)

Could someone explain the difference between the penultimate and the final expressions?

Thank you in advance!

--
Best,
Evgeny

lezed1

unread,
Jan 25, 2018, 2:06:35 AM1/25/18
to ocaml-core
Hi Evgeny,

I'll add a few more parentheses to clear up exactly what's going on (all according to the precedences of OCaml in this table). First, let's consider your penultimate example.

(return 1) >>| (fun r -> (2 >>| (fun r' -> (r, r'))));;

If you look at the part closer to the end, you find this subexpression:

2 >>| (fun r' -> (r, r'))

The typecheck error in the penultimate expression was that `2` is not a `('a, 'e) result`. We can fix this by changing `2` to `return 2`, but the evaluation is not what was originally intended:

utop # (return 1) >>| (fun r -> ((return 2) >>| (fun r' -> (r, r'))));;
- : ((int * int, 'a) result, 'b) result = Ok (Ok (1, 2))  

Now the evaluates to a nested result. This is because each map (`>>|`) will wrap the returned expression. If you expanded this to (1, 2, 3, 4, 5) using all maps, you would ended up with a five nested result - one for each map. Since you do not want the additional nesting, you can convert all but the ultimate map (`>>|`) into a bind (`>>=`). This will fix the nested problem and results in this expression:

utop # (return 1) >>= (fun r -> ((return 2) >>| (fun r' -> (r, r'))));;
- : (int * int, 'a) result = Ok (1, 2) 

This fixed up expression is your ultimate expression!

In case the more technical explanation is hard to follow (which I expect it to be), here is a different way to approach constructing the final expression. Your first expression (the single return) is straightforward. Trying to build the second expression right after, you insert `fun r -> 2 >>|` in the middle of first expression. It may be clearer to instead not break up the first expression and instead prepend `return 2 >>= fun r' -> ` which is basically your third expression (with a few numbers/names swapped).

Hopefully that clears it up! If anything is still not clear, please let me know, I'm more than happy to try to explain anything in a different way (especially since I don't think this explanation is particularly clear).

--
Zander!
Reply all
Reply to author
Forward
0 new messages