Как объявить тип карты в Reason ML?

Одним из преимуществ Reason ML перед JavaScript является то, что он предоставляет тип Map, который использует структурное равенство, а не ссылочное равенство.

Однако я не могу найти примеров использования этого.

Например, как мне объявить тип scores, который представляет собой преобразование строк в целые числа?

/* Something like this */
type scores = Map<string, int>; 

И как мне построить экземпляр?

/* Something like this */
let myMap = scores();

let myMap2 = myMap.set('x', 100);

person sdgfsdh    schedule 16.02.2018    source источник


Ответы (2)


Стандартная библиотека Map на самом деле уникальна в мире языков программирования в том смысле, что это функтор модуля, который вы должны использовать для создания модуля карты для вашего конкретного типа ключа (и поэтому справочная документация по API находится в Map.Make):

module StringMap = Map.Make({
  type t = string;
  let compare = compare
});

type scores = StringMap.t(int);

let myMap = StringMap.empty;
let myMap2 = StringMap.add("x", 100, myMap);

Существуют и другие структуры данных, которые вы можете использовать для создания функциональных возможностей, подобных карте, особенно если вам нужен строковый ключ. Там сравнение различных методов в кулинарной книге BuckleScript. Все, кроме Js.Dict, доступны вне BuckleScript. BuckleScript также поставляется с новой структурой данных карты в его стандартной бета-библиотеке, которая Я еще не пробовал.

person glennsl    schedule 16.02.2018
comment
Итак, тип ключа определяется в функторе модуля (это новая для меня концепция), а тип значения определяется как параметр типа для функции t? Расскажите, почему это было реализовано в два этапа? Исходя из F #, это кажется очень странным. - person sdgfsdh; 16.02.2018
comment
StringMap.t - это тип с параметром типа, а не функция в строгом смысле слова, хотя концептуально вы можете (и должны!) Думать о нем как о функции над типами. Точно так же функтор модуля - это просто функция над модулями, она принимает модуль (или несколько) и возвращает модуль. - person glennsl; 16.02.2018
comment
Я не совсем уверен, почему он был реализован как функтор, но одна из возможных мотиваций - просто потому, что вы можете. В F # я не думаю, что вы можете, потому что модульная система недостаточно мощна. Для неизменяемой структуры данных это, вероятно, также делает реализацию более чистой, немного более производительной и менее загружающей память, поскольку без жесткого кодирования функции сравнения вам придется переносить ее в оболочке, которая должна дублироваться каждый раз, когда вы добавляете или удалить узел с карты. - person glennsl; 16.02.2018
comment
Еще один важный момент - тип карты должен зависеть как от типа ключа, так и от функции сравнения. В противном случае можно было бы попытаться объединить две карты, построенные с разными функциями сравнения, что привело бы к совершенно неустойчивому поведению. Функтор предоставляет удобный способ сделать тип карты зависимым от всего модуля параметров, включая функцию сравнения. Другие чистые способы достижения этого результата более сложные (см. Модуль Janestreet Base.Map для хорошего примера) - person octachron; 17.02.2018

Если вы просто имеете дело с Map<string, int>, Map.String Белта сделает свое дело.

module MS = Belt.Map.String;

let foo: MS.t(int) = [|("a", 1), ("b", 2), ("c", 3)|]->MS.fromArray;

Эргономика версии Belt немного менее болезненна, и это неизменные карты для загрузки! Также внутри пояса есть Map.Int. Для других типов ключей вам нужно будет определить свой собственный компаратор. Это возвращает нас к чему-то похожему на двухэтапный процесс @glennsl, описанный выше.

person wegry    schedule 28.11.2018