Есть ли в OCaml общие функции map () / redu ()?
-
06-07-2019 - |
Вопрос
В Python map () работает с любыми данными, которые следуют протоколу последовательности. Это правильно, независимо от того, передаю ли я строку, список или даже кортеж.
Разве я не могу иметь свой торт в OCaml? У меня действительно нет другого выбора, кроме как посмотреть на тип коллекции, которую я использую, и найти соответствующий List.map или Array.map, Buffer.map или String.map? Некоторые из них даже не существуют! Это то, что я прошу за необычное? Я должен что-то упустить.
Решение
Наиболее близким к этому является модуль Enum
в аккумуляторы OCaml включены (ранее Extlib ). Enum
определяет карты и складывает поверх Enum.t
; вам просто нужно использовать преобразование в / из Enum.t
для вашего типа данных. Преобразования могут быть довольно легкими, потому что Enum.t
ленив.
Что вам действительно нужно, так это классы типов в стиле Haskell, например Foldable
и Functor
(который обобщает " карты "). Библиотеки Haskell определяют экземпляры Foldable
и Functor
для списков, массивов и деревьев. Еще одна важная методика - " Зачистить свою заготовку " подход к общему программированию. Поскольку OCaml не поддерживает классы типов или полиморфизм с более высоким родом , я не думаю, что Вы сможете выразить подобные шаблоны в своей системе типов.
Другие советы
В OCaml есть два основных решения:
<Ол> Жак Гарриге уже реализовал синтаксически легкий, но неэффективный подход для многих структур данных несколько лет назад. Вы просто заключаете коллекции в объекты, которые предоставляют метод map
. Затем вы можете сделать collection # map
, чтобы использовать функцию map для любого вида коллекции. Это более общее, чем ваши требования, поскольку оно позволяет заменять различные типы структур данных во время выполнения . Однако на практике это не очень полезно, поэтому этот подход никогда не получал широкого распространения.
Синтаксически более тяжелое, но эффективное, надежное и статичное решение состоит в использовании функторов для параметризации вашего кода в структуре данных, которую вы используете. Это упрощает повторное использование кода с различными структурами данных. См. Перевод Маркуса Моттла на OCaml книги Окасаки «Чисто функциональные структуры данных». для некоторых замечательных примеров.
Если вы не ищете такой мощности и просто хотите краткости, то, конечно, вы можете просто создать псевдоним модуля с более коротким именем (например, module S = String).
Проблема в том, что каждый контейнер имеет свое представление и требует иного кода для сопоставления / сокращения для его итерации. Вот почему есть отдельные функции. Большинство языков предоставляют некоторый общий интерфейс для контейнеров (такой как протокол последовательности, который вы упомянули), поэтому такие функции, как map / lower, могут быть реализованы абстрактно, но это не сделано для упомянутых вами типов.
Пока вы определяете сравнение типов t и val (: t-> g-; int) в своем модуле, Map.Make предоставит вам нужную карту. Р>