Добавление к строковой карте в OCaml - PullRequest
8 голосов
/ 07 октября 2010

Я пытался выяснить, что, по моему мнению, является довольно простой задачей, а именно добавление записей на карту Strings в OCaml изнутри функции.Соответствующие элементы приведены ниже:

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;;

Я продолжаю получать загадочное сообщение «Синтаксическая ошибка», но мне еще не удалось найти решение даже после того, как код был сведен к нулю.Я могу добавить к String Map одну команду, но если я попытаюсь запустить let m = StringMap.add hd 1 m изнутри функции, она не запустится.Я уверен, что это простая проблема, но кто-то может помочь?Спасибо.

Ответы [ 2 ]

15 голосов
/ 07 октября 2010

Кажется, есть несколько проблем с вашим кодом. Но сначала вот пример того, как делать то, что вы пытаетесь сделать:

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"]

Некоторые комментарии к оригинальному коду:

  • двойные точки с запятой используются, чтобы сообщить циклу REPL, что вы хотите, чтобы он использовал ваш код. Вы должны избегать их, если не используете его.
  • одиночные точки с запятой используются для разделения императивных выражений, например после назначения. Здесь у вас есть выражение let с синтаксисом «let <..> in <..>», поэтому вы используете точку с запятой после него неправильно. («let a = ...» без «in» является конструкцией верхнего уровня, а не тем, что вы можете использовать локально).
  • StringMap (и большинство других структур в ocaml) являются функциональными, а не обязательными. Вы не можете изменить 'm', который вы объявили в первой строке. Вы должны построить структуру и, наконец, вернуть полностью построенную структуру в конце цикла.
10 голосов
/ 07 октября 2010

Ваш источник путаницы заключается в том, что вы неправильно поняли значение конструкции 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...