Масштабный дизайн в Haskell? [закрыто]

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

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

7262627 -> 8172
7262628 -> 819
7262629 -> 1732
...
7262631 -> 3558

Здесь достаточно ясно (учитывая несколько минут и калькулятор), что при увеличении входа на 1, выход увеличивается на 913 по модулю 8266 (т. Е. Простой линейный конгруэнтный генератор ).

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

Другие способы приближения к этой проблеме состоят в том, чтобы посмотреть на крайности (максимальные, минимальные значения), распределение (приводящее к частотном анализе ), направление (числа всегда увеличиваются? ) и (если это разрешено) рассмотрим контекст, в котором были найдены наборы данных. Например, некоторые типы PIN-кодов всегда содержат повторенную цифру, чтобы облегчить их запоминание (я не говорю, что PIN-код может быть выведен из чего-либо другого - просто повторяющаяся цифра равна единице нет разряд беспокоиться!).

566
задан Yvette Colomb 6 November 2018 в 00:07
поделиться

3 ответа

Я немного говорю об этом в Проектирование больших проектов на Haskell и в Проектирование и реализация XMonad. Инженерное дело в целом - это управление сложностью. Основными механизмами структурирования кода в Haskell для управления сложностью являются:

Система типов

  • Используйте систему типов для обеспечения абстракций, упрощая взаимодействия.
  • Принудительное использование ключевых инвариантов с помощью типов
    • (например, что определенные значения не могут выйти из некоторой области действия)
    • Этот определенный код не выполняет операций ввода-вывода, не касается диска
  • Обеспечение безопасности: проверенные исключения (Возможно / Либо), избегайте смешивания концепций (Word, Int, Address)
  • Хорошие структуры данных (например, застежки-молнии) могут сделать некоторые классы тестирования ненужными, поскольку они исключают, например, статические ошибки вне границ.

Профилировщик

  • Обеспечивает объективное свидетельство профилей кучи и времени вашей программы.
  • В частности, профилирование кучи - лучший способ избежать ненужного использования памяти.

Чистота

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

Тестирование

  • QuickCheck + Haskell Code Coverage, чтобы гарантировать, что вы тестируете то, что вы не можете проверить с помощью типов.
  • GHC + RTS отлично подходит, если вы тратите слишком много времени на сборку мусора.
  • QuickCheck также может помочь вам определить чистые, ортогональные API для ваших модулей. Если свойства вашего кода сложно описать, вероятно, они слишком сложны. Продолжайте рефакторинг, пока у вас не будет чистого набора свойств, которые могут протестировать ваш код и хорошо составлены. Тогда код, вероятно, тоже хорошо спроектирован.

Монады для структурирования

  • Монады фиксируют ключевые архитектурные проекты в типах (этот код обращается к оборудованию, этот код является однопользовательским сеансом и т. Д.)
  • Например. монада X в xmonad точно фиксирует проект, в каком состоянии какие компоненты системы видны.

Классы типов и экзистенциальные типы

  • Используйте классы типов для обеспечения абстракции: скрывайте реализации за полиморфными интерфейсами.

Параллелизм и параллелизм

  • Внедрите par в свою программу, чтобы превзойти конкурентов с помощью простого компонуемого параллелизма.

Рефакторинг

  • В Haskell можно выполнять рефакторинг очень часто . Типы гарантируют, что ваши крупномасштабные изменения будут безопасными, если вы используете их с умом. Это поможет масштабировать вашу кодовую базу. До завершения убедитесь, что ваш рефакторинг вызовет ошибки типа.

Используйте FFI с умом

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

Мета-программирование

  • Немного шаблонного Haskell или дженериков может удалить шаблон.

Упаковка и распространение

  • Используйте Кабал. Не сворачивайте свою собственную систему сборки. (РЕДАКТИРОВАТЬ: на самом деле вы, вероятно, захотите использовать Стек сейчас для начала.).
  • Используйте Haddock для хорошей документации по API.
  • Такие инструменты, как graphmod , могут отображать структуры вашего модуля.
  • По возможности полагайтесь на версии библиотек и инструментов платформы Haskell. Это стабильная база. (РЕДАКТИРОВАТЬ: Опять же, в наши дни вы, вероятно, захотите использовать Стек для получения стабильной базы и работы.)

Предупреждения

  • Используйте -Wall , чтобы сохранить ваш код чистый от запахов. Вы также можете посмотреть на Agda, Isabelle или Catch для большей уверенности. Для проверки, похожей на линт, см. Отличный hlint , который предложит улучшения.

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

В общем: разложите логические единицы вашей системы на наименьшие возможные ссылочно прозрачные компоненты,затем реализовать их в модулях. Глобальные или локальные среды для наборов компонентов (или внутри компонентов) могут быть отображены на монады. Используйте алгебраические типы данных для описания основных структур данных. Широко поделитесь этими определениями.

519
ответ дан 22 November 2019 в 22:11
поделиться

Проектирование больших программ на Haskell не сильно отличается от проектирования на других языках. Программирование в большом - это разбиение вашей проблемы на управляемые части, и то, как соединить их вместе; язык реализации менее важен.

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

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

43
ответ дан 22 November 2019 в 22:11
поделиться

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

  1. В конце концов, вы живете в стеке монада-трансформер. В самом низу находится IO. Выше него каждый основной модуль (в абстрактном смысле, а не в смысле модуль в файле) отображает свое необходимое состояние на слой в этом стеке. Таким образом, если код подключения к базе данных спрятан в модуле, вы пишете его над типом MonadReader Connection m => ... -> m ... и тогда ваши функции базы данных всегда могут получить свое подключение без того, чтобы функции из других модулей знали о его существовании. В итоге вы можете получить один слой, несущий соединение с базой данных, другой - конфигурацию, третий - различные семафоры и mvars для разрешения параллелизма и синхронизации, третий - обработку лог-файлов и т.д.

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

Дополнение (извлечено из комментариев; спасибо Lii и liminalisht) -
больше обсуждений различных способов нарезки большой программы на монады в стеке:

Ben Kolera дает отличное практическое введение в эту тему, а Brian Hurt обсуждает решения проблемы lifting monadic actions in your custom monad. Джордж Уилсон показывает, как использовать mtl для написания кода, который работает с любой монадой, реализующей необходимые типоклассы, а не с вашей пользовательской монадой. Карло Хамалайнен написал несколько коротких, полезных заметок, резюмирующих выступление Джорджа.

118
ответ дан 22 November 2019 в 22:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: