我试图学习ocaml但遇到函数组合运算符问题|>。
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
我认为x |> f
应该等同于f(x)
。为什么Option.value_exn(Some(1))
有效但Some(1) |> Option.value_exn
无效?
答案 0 :(得分:5)
不,它们不相同。您可以将|>
运算符定义为:
utop # let (|>) a f = f a;;
val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun>
因此,它需要类型'a
和函数'a -> 'b
的某些值。
但是,由于命名参数,Option.value_exn
的类型不是'a -> 'b
:
utop # Option.value_exn;;
- : ?here:Lexing.position ->
?error:Base.Error.t -> ?message:string -> 'a option -> 'a
您可以明确指定所有命名参数(实际上没有意义)
utop # Some 1 |> Option.value_exn ~here:Lexing.dummy_pos ~error:(Error.of_string "dummy") ~message:"dummy";;
- : int = 1
或只是使用lambda来包装它
utop # Some 1 |> fun x -> Option.value_exn x;;
- : int = 1
答案 1 :(得分:3)
the Ocaml manual中描述了类型推断和可选/标记参数的困难。它提到解决问题的正确方法是为麻烦的参数提供明确的类型归属,在本例中为Option.value_exn
。确实
Some(1) |> (Option.value_exn : int option -> int);;
的工作原理。该手册进一步解释了
在期望类型是非标签函数类型且参数是期望可选参数的函数的特定情况下,编译器将尝试通过为所有参数传递None来转换参数以使其与期望类型匹配可选参数
但似乎Option.value_exn
的多态性会干扰这种机制。
let f ?(message = "") x = x in 1 |> f;;
出于同样的原因。