Pardon my query if this is something very obvious, I am new to both OCaml and functional programming.
I was experimenting with Modules and I got this error Syntax error for the code below at the ‘in’ definition
module MyList = struct
type 'a mylist =
| Nil
| Cons of 'a * 'a mylist
let rec map f = function
| Nil -> Nil
| Cons(h, t) -> Cons (f h, map f t)
let rec fold_left (f:'a -> 'a -> 'a) acc = function
| Nil -> acc
| Cons(h, t) -> fold_left f (f acc h) t
end
let a = MyList.map (fun x -> x + 1) (Cons(1, Cons(2, Nil))) in
let b = MyList.fold_left ( + ) 0 a in
Printf.printf "%d\n" b
and after some debugging, I could fix it as
module MyList = struct
type 'a mylist =
| Nil
| Cons of 'a * 'a mylist
let rec map f = function
| Nil -> Nil
| Cons(h, t) -> Cons (f h, map f t)
let rec fold_left (f:'a -> 'a -> 'a) acc = function
| Nil -> acc
| Cons(h, t) -> fold_left f (f acc h) t
end
let a = MyList.map (fun x -> x + 1) (Cons(1, Cons(2, Nil)));;
let b = MyList.fold_left ( + ) 0 a in
Printf.printf "%d\n" b
Why does the type deducer fail when I use nested ‘let in’ syntax? If this is expected behavior, wouldn’t it be more appropriate to provide a clearer error message instead of just Syntax error?
Let’s first reindent this block of code according to its meaning:
let a =
MyList.map (fun x -> x + 1) (Cons(1, Cons(2, Nil))) in
let b = MyList.fold_left ( + ) 0 a in
Printf.printf "%d\n" b
which makes it clearer why this is a syntax error.
This is indeed a very misleading error, which best remediation comes from the very fact that it occurs so frequently that you will quickly learn to reckognize and fix it.
The issue is that top level definitions use almost, but quite not exaclty, the same syntax as in-block definitions: let x = v vs let x = v in ...
Note: your solution was to add the REPL delimiter (the double semi-colon). Notice that, unless you actualy intend to copy and paste this code into the REPL, the double-semi-colon is useless and can just as well be ommited.
Note that a single expression (eg let ... in ...) is not allowed at the top-level of a module. Instead, only the form let ... = ... (without the in) is allowed, which defines a top-level binding valid for the rest of the file. If you want to execute an expression at the top-level of a module (eg for its side-effects, as in your example), you can reuse this same construct, using let () = ...:
let () =
let a = ... in
let b = ... in
Printf.printf ...
If you want to learn more about the syntax allowed at top-level of a module, I recommend taking a look at OCaml - The OCaml language.
In full generality, sure…I am not knowledgeable enough to assert whether something simpler could not be done in some simple cases, though, so I try not to discount the possibility outright
Well, yes, and no. It is true that it is indeed possible to enter a top-level expression followed by a double semicolon. This usage, which is borrowed from the toplevel ocaml, is discouraged outside of the REPL nowadays and the use via let () = ... is preferred as a more regular alternative. Having said that, some old-timers still prefer it because it can sometimes result in better localisation of syntax errors. So as you can see, there’s something for everyone