I deliberately added x to the end of this function
let myMax x y =
if x > y then x else y
x
I was expecting that x and y arguments are still of ‘a type, but I get this signature instead:
myMax : x:unit -> y:unit -> unit
Why these arguments inferred to have a unit type?
Edit: Thank you @gilles for the answer. Consider these two functions:
let foo x y =
0 // warning
x
val foo : x:'a -> y:'b -> 'a
let foo2 x y =
if x > y then x else y // no warning
x
val foo2 : x:unit -> y:unit -> unit
What makes the two signatures different? Seems like in the second function the compiler interpret the result of the comparison –either x or y- as unit
Let's write a simpler example:
> fun x -> x; 0;;
val it : unit -> int = <fun:clo@5>
In a compound expression, the expression before the semicolon/newline operator must have unit type. If you want to use an expression with a “real” value (i.e. anything of a type other than unit), you need to ignore it explicitly, or bind it to a variable-less pattern. The compiler reminds you if the expression's type can't be unified with unit
:
> fun x -> 0; x;;
fun x -> 0; x;;
---------^
stdin(7,10): warning FS0020: This expression should have type 'unit', but has type 'int'.
Use 'ignore' to discard the result of the expression,
or 'let' to bind the result to a name.
val it : x:'a -> 'a = <fun:clo@7-1>
It would be possible to have a typing rule that allows any type before ;
— the value is ignored, after all, so its type doesn't matter — but that would make it easy to accidentally discard a return value that matters. So if you want to ignore the value, do so explicitly:
let myMax x y =
ignore (if x > y then x else y)
x
or
let myMax x y =
let _ = if x > y then x else y
x
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With