I have been trying to figure out what I figure is a pretty simple task, namely adding entries to a map of Strings in OCaml from within a function. The relevant elements are below:
module StringMap = Map.Make (String);;
let m = StringMap.empty;;
let rec count ke =
match ke with
| [] -> []
| hd::tl ->
begin
let m = StringMap.add hd 1 m;
[hd] @ count tl
end;;
I keep receiving the cryptic "Syntax Error" message, but I have yet to find a solution even after stripping the code down to basically nothing. I can add to the String Map with a single command, but if I try to run let m = StringMap.add hd 1 m
from within function, it fails to run. I am sure this is a simple problem, but can someone please help? Thanks.
There seem to be a few problems with your code. But first, here is an example on how to do what you are trying to do:
module StringMap = Map.Make (String)
let rec count m ke =
match ke with
| [] -> m
| hd :: tl -> count (StringMap.add hd 1 m) tl
let m = count StringMap.empty ["foo"; "bar"; "baz"]
Some comments on the original code:
Your source of confusion is that you've misunderstood the meaning of the let
construct. It does not modify an object: it's not an assignment statement (. The let
construct gives a name to a value. The syntax of the let
construct is
let
name =
value in
expression
This causes name to refer to value in expression. The value is computed once, before binding the name to it. The scope of name is expression, so you can't use it to refer to value outside expression (the value, on the other hand, lives on until garbage collected).
The top-level let
construct is similar to the one in expressions, but does not have the in
expression part. The scope of the name is the rest of the program (it's as though there was an in
part containing everything below, at least until you get to modules).
You're trying to modify the top-level m
, but that is not let
's job: you would need an assignment for that. Ocaml has an assignment operator, :=
, which assigns to an existing reference. A reference is an object that can be modified. This is not automatic in Ocaml: unlike languages such as C, Java and Lisp, Ocaml does not use a single language feature to give names to values and to create modifiable storage. The ref
function creates a modifiable object; you assign it with :=
and use the !
operator to get its value:
let r_m = ref StringMap.empty;; (*the type of r_m is 'a StringMap.t ref*)
let rec count ke = match ke with
| [] -> []
| hd::tl -> r_m := StringMap.add hd 1 !r_m; [hd] @ count tl;;
This is however not very good Ocaml style. Ocaml supports this imperative style, but you should avoid it because imperative programming is more error-prone than functional programming. The functional style is to create a new value whenever you want to modify an object. Note that maps created by the Map
module are designed to support this style: add
returns a new object which coexists with the old object (i.e. it's a persistent data structure). Switching to a functional style requires that you change the interface of the count
function; it's something that you'd want to do anyway, to be able to use the count
function on different maps by passing the map as an argument. I refer you to Sami's answer for example code in good Ocaml style.
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