Подтвердить что ты не робот

Типы данных Haskell используют хорошие практики

Чтение "Реальный мир Haskell" я нашел интересный вопрос о типах данных:

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

Это, как правило, очень плохо в императив (особенно OO) Языки... не рассматривается как проблема в Haskell? источник в комментариях RWH

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

4b9b3361

Ответ 1

То, что вы описываете, обычно называется проблемой выражения - http://en.wikipedia.org/wiki/Expression_Problem.

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

Все, что сказано, есть ряд вещей, которые вы можете сделать, чтобы уменьшить сцепление.

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

  • Представьте свои структуры данных как более абстрактные. Это означает реализацию всех соответствующих классов классов. Это поможет определить функции библиотеки, поскольку вы получите бесплатный доступ к любому из классов типов, которые вы реализуете, например, для операций над Functor или Monad.

  • Скрыть (как можно больше) конструкторы любого типа. Конструкторы раскрывают детали реализации и будут стимулировать сцепление. Подсказка: это связано с определением хорошего api для взаимодействия с вашим типом, потребители вашего типа должны редко, если вообще когда-либо, использовать конструкторы типов.

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

Ответ 2

В дополнение к тому, что было сказано:

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

Второй метод, как указал Хибберд, заключается в использовании сгибов, карт, разворачиваний и других комбинаторов рекурсий для определения ваших функций. Когда вы пишете функции с использованием функций более высокого порядка, часто небольшие изменения в базовом типе данных могут быть рассмотрены в объявлениях экземпляров для Functor, Foldable и т.д.

Ответ 3

Во-первых, я хотел бы упомянуть, что, на мой взгляд, существует два типа связей:

  • Тот, который заставляет ваш код перестать компилироваться, когда вы меняете его, и забываете изменить другой

  • Тот, который делает ваш код ошибкой при его изменении и забывает изменить другой

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

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

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

bad (Blah _ y) = ...

good (Blah{y = y}) = ...

Избегайте чрезмерного использования кортежей, особенно те, которые находятся за пределами 2-х кортежей, и свободно создают записи/новые типы вокруг вещей, чтобы избежать позиционного значения.