Hello, folks!
Sometimes, when I’m writing a bigger function and I can’t figure out where my type errors are coming from, I like to add explicit type annotations to see where my code creates problems for the type checker as such:
let rec pow_mod (x : int) (y : int) (m : int): int =
if y <= 0 then 1
else if y mod 2 = 0 then pow_mod (x * x mod m) (y / 2) m
else x * pow_mod x (y - 1) m mod m
Now this works like a charm but is quite cumbersome (adding lots of parentheses and jumping around a lot).
Alternatively, one could write it like this
let rec pow_mod : int -> int -> int -> int =
fun x y m -> ...
which makes type annotations much nicer to add when needed and remove later: one needs to only insert code after the identifier name and can easily mark that whole section for deletion. Unfortunately this is quite ugly (in my opinion), so I would still need to rewrite that section to remove the fun x y m ->
part and integrate the arguments into the let
binding.
Ideally I would like to just add a typehint like this
val pow_mod : int -> int -> int -> int
let rec pow_mod = ...
which sadly is not possible to my knowledge (val
is only available in .mli
files)
So I have two questions:
- If you have any tips on how to achieve something similar more seamlessly that would be great!
- I find the idea of toplevel type annotations with
val foo : bar -> baz
in normal.ml
files as an alternative to inline type annotationslet foo (x : bar) : baz = ...
very useful. Are there good reasons for why this is not possible? Could this perhaps be a new feature that might improve ergonomics?