Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ocaml function application operator fails

Tags:

ocaml

I'm trying to learn ocaml but ran into an issue with the function composition operator |>.

utop # #require "core";;
utop # open Core;;
utop # Option.value_exn(Some(1));;
- : int = 1
utop # Some(1) |> Option.value_exn;;
Error: This expression has type
         ?here:Base__Source_code_position0.t ->
         ?error:Base.Error.t -> ?message:string -> 'a option -> 'a
       but an expression was expected of type int option -> 'b

I thoght x |> f was supposed to be equivalent to f(x). Why does Option.value_exn(Some(1)) work but not Some(1) |> Option.value_exn?

like image 296
rymdhund Avatar asked Jan 30 '23 02:01

rymdhund


2 Answers

No, they aren't equivalent. You can define |> operator as:

utop # let (|>) a f = f a;;
val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun>

So, it expects some value of type 'a and a function 'a -> 'b.

But, type of Option.value_exn is not 'a -> 'b due to named parameters:

utop # Option.value_exn;;
- : ?here:Lexing.position ->
    ?error:Base.Error.t -> ?message:string -> 'a option -> 'a

You can specify all named parameters explicitly (makes zero sense actually)

utop # Some 1 |> Option.value_exn ~here:Lexing.dummy_pos ~error:(Error.of_string "dummy") ~message:"dummy";;
- : int = 1

or just use lambda to wrap it

utop # Some 1 |> fun x -> Option.value_exn x;;
- : int = 1
like image 142
Stas Avatar answered Feb 17 '23 12:02

Stas


The difficulties with type inference and optional/labeled arguments is described in the Ocaml manual. It mentions that the right way to resolve the issue is to give an explicit type ascription for the troublesome argument, in this case Option.value_exn. Indeed

Some(1) |> (Option.value_exn : int option -> int);;

works. The manual further explains that

in the specific case where the expected type is a non-labeled function type, and the argument is a function expecting optional parameters, the compiler will attempt to transform the argument to have it match the expected type, by passing None for all optional parameters

but it appears that the polymorphism of Option.value_exn interferes with this mechanism. Evidence that it is the polymoprhism that causes the trouble is seen in the failure of

let f ?(message = "") x = x in 1 |> f;;

for the same reason.

like image 26
Geoff Reedy Avatar answered Feb 17 '23 12:02

Geoff Reedy