Ваш источник путаницы заключается в том, что вы неправильно поняли значение конструкции let
. Он не изменяет объект: это не оператор присваивания (. Конструкция let
дает name значению . Синтаксис конструкции let
:
let
имя =
значение in
выражение
Это заставляет имя ссылаться на значение в выражении . Значение вычисляется один раз перед привязкой имени к нему. Область действия name равна выражение , поэтому его нельзя использовать для ссылки на значение вне выражение (значение на с другой стороны, живет до тех пор, пока мусор не будет собран).
Конструкция верхнего уровня let
аналогична конструкции в выражениях, но не имеет части in
expression . Область действия имени - остальная часть программы (как если бы была часть in
, содержащая все ниже, по крайней мере, пока вы не дойдете до модулей).
Вы пытаетесь изменить m
верхнего уровня, но это не работа let
: для этого вам понадобится задание. У Ocaml есть оператор присваивания, :=
, который присваивает существующую ссылку . Ссылка - это объект, который можно изменить. В Ocaml это не происходит автоматически: в отличие от языков, таких как C, Java и Lisp, Ocaml не использует единую языковую функцию для присвоения имен значениям и создания изменяемого хранилища. Функция ref
создает модифицируемый объект; Вы назначаете его с помощью :=
и используете оператор !
, чтобы получить его значение:
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;;
Это, однако, не очень хороший стиль Ocaml. Ocaml поддерживает этот императивный стиль, но вы должны избегать его, потому что императивное программирование более подвержено ошибкам, чем функциональное программирование. Функциональный стиль заключается в создании нового значения всякий раз, когда вы хотите изменить объект. Обратите внимание, что карты, созданные модулем Map
, разработаны для поддержки этого стиля: add
возвращает новый объект, который сосуществует со старым объектом (т. Е. Это постоянная структура данных ). Переключение на функциональный стиль требует изменения интерфейса функции count
; это то, что вы хотели бы сделать в любом случае, чтобы иметь возможность использовать функцию count
на разных картах, передавая карту в качестве аргумента. Я отсылаю вас к ответу Сами , например, коду в хорошем стиле Ocaml.