Composition of two arguments function returning options

disclaimer : I am not even sure the title is correct.

Provided the example below :

type error1 = [`A]
type error2 = [ error1 | `B ]

type a1 = int 
type a2 = int 

(* conversion error1 to error2 if needed ?*)
let error1_to_error2 (z:error1) = match z with 
   | `A -> (`A:error2)

let f (x1:a1) (x2:a2) = 
  if x1 < 0 then Error (`A:error2)
  else if x2 < 0 then Error (`B:error2)
  else Ok (x1 + x2)

let v : (a1,error1) result = Ok 1 
let w : (a2,error2) result = Ok 2 

How am I supposed to compute the equivalent of f 1 2 using respectively v instead of 1 and w instead of 2 without accessing the content of result values ?

I know Result.bind & co are supposed to help here, maybe currying/uncurrying, but I shall admit I am lost. Any help (at least a direction) ?

Here is something to get you started:

type error1 = [`A]
type error2 = [ error1 | `B ]

type a1 = int
type a2 = int

(* conversion error1 to error2 if needed ?*)
let error1_to_error2 (z:error1) = match z with
   | `A -> (`A:error2)

let f (x1:a1) (x2:a2) =
  if x1 < 0 then Error (`A:error2)
  else if x2 < 0 then Error (`B:error2)
  else Ok (x1 + x2)

let ( let* ) = Result.bind

let result =
  let* v = Ok 1 in
  let* w = Ok 2 in
  f v w

let () =
  match result with
  | Error _ -> failwith "error"
  | Ok _ -> print_endline "ok"

Will this help?

let v_as_error2 : (_, error2) result = (v :> (a1, error2) result)

You can cast your values if containers have right variance. (Result type is an immutable functor, which gives you covariant container)

Thank you. I understand I need to dig further into let binding operator. Also the tutorial on the ocaml web site mention it, this is not enough to understand how it works really. The manual is necessary to understand the behavior of this syntactic sugar

Thanks Kakadu,

If I barely understand what ‘container’ refers to, I guess I miss the ‘variance’ part, not talking about covariant container.

Learn how to define bind yourself for different types and how to use it without the syntax sugar. This will demystify.

This source may help: https://courses.cs.cornell.edu/cs3110/2021sp/textbook/adv/monads.html

I think I am fine with bind alone, without the let* operator. But the introduction of such operator changes significantly the syntax…which is not a function-like syntax anymore…that is what is disturbing me I guess.

Thanks for the pointer.

Oh nice! In that case, perhaps all you need to see the functional-like syntax under the sugar is to recall that let-binding like

let x = foo in ...

Can be de-sugared into the application of an abstraction

(fun x -> ... ) foo

If you consider the implementation of bind function and the uses of its infix form (>>=) in this light, alongside the same expressions using binding operators, it will probably click :slight_smile:

1 Like

That’s it. I think this is the rule I have to familiarize with.

NB : the manual says foo (fun x → …) though, if I follow you correctly :slight_smile:

The section you linked to is talking about binding operators aka let-operators like let*. Shon is talking about the regular let which you can think of as desugaring into a function application.

1 Like