Достижение правильных абстракций с системой типов Haskell - PullRequest
7 голосов
/ 26 августа 2011

У меня проблемы с элегантным использованием системы типов Haskell.Я уверен, что моя проблема распространена, но я не знаю, как ее описать, за исключением тех терминов, которые характерны для моей программы.

Понятия, которые я пытаюсь представить:*

точки данных, каждая из которых принимает одну из нескольких форм, например (идентификатор, количество случаев, количество элементов управления), (идентификатор, количество случаев, население)

наборы точек данных и агрегированной информации: (набор идентификаторов, общее количество случаев, общее количество элементов управления), с функциями для добавления / удаления точек (поэтому для каждого множества точек есть соответствующий набор множеств)

Я мог бы иметь класс типов точек и определить каждое разнообразие точек как свой собственный тип.В качестве альтернативы я мог бы иметь один тип точек и разные конструкторы данных для каждого сорта.Аналогично для наборов точек.

У меня есть по крайней мере одна проблема с каждым подходом:

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

  • Без классов типов: я бы не стал экспортировать конструкторы данных, скажем, из модуля Point (предоставляя другие, более безопасные функции для создания нового значения).Без конструкторов данных я не смогу определить, для какого сорта задано значение Point.

Какой дизайн может помочь минимизировать эти (и другие) проблемы?

Ответы [ 3 ]

4 голосов
/ 27 августа 2011

Чтобы немного расширить ответ sclv, существует расширенное семейство тесно связанных концепций, которые сводятся к предоставлению некоторых средств деконструкции значения: катаморфизмы, которые представляют собой обобщенные складки;Церковное кодирование, которое представляет данные своими операциями и часто эквивалентно частичному применению катаморфизма к значению, которое оно разрушает;Преобразования CPS, где кодировка Черча напоминает сопоставленное сопоставление с шаблоном, которое принимает отдельные продолжения для каждого случая;представление данных в виде набора операций, которые их используют, обычно называемые объектно-ориентированным программированием;и т. д.

В вашем случае вам нужен абстрактный тип , то есть тот, который не экспортирует свое внутреннее представление, но не полностью запечатанный, т.е.что оставляет представление открытым для функций в модуле, который его определяет.По той же схеме следуют такие вещи, как Data.Map.Map.Вы, вероятно, не хотите идти по пути класса типов, поскольку, похоже, вам нужно работать с различными точками данных, а не с произвольным выбором точки данных одного типа.

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

3 голосов
/ 27 августа 2011

С последним решением (без классов типов) вы можете экспортировать катаморфизм для типа, а не для конструкторов.

data MyData = PointData Double Double | ControlData Double Double Double | SomeOtherData String Double

foldMyData pf cf sf d = case d of
       (PointData x y) -> pf x y
       (ControlData x y z) -> cf x y z
       (SomeOtherData s x) -> sf s x

Таким образом, у вас есть способ разделить ваши данные на что угодно (в том числе просто игнорировать значения и передать функции, которые возвращают, какой тип конструктора вы использовали) без предоставления общего способа построения ваших данных.

2 голосов
/ 27 августа 2011

Я считаю, что подход на основе классов типов лучше, если вы не собираетесь смешивать разные точки данных в одной структуре данных.

Упомянутая вами проблема конфликта имен может быть решена путем создания отдельного класса типов для каждого отдельного поля, например:

class WithCases p where
    cases :: p -> NumberOfCases 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...