Хорошие стандарты кодирования Haskell

Может ли кто-нибудь предоставить ссылку на хороший стандарт кодирования для Haskell? Я нашел этот и этот, но они далеки от всеобъемлющего. Не говоря уже о том, что HaskellWiki включает такие "драгоценные камни", как "классы использования с осторожностью" и "определение символических идентификаторов инфикс следует оставлять только библиотечным писателям".

Ответ 1

Действительно сложный вопрос. Надеюсь, ваши ответы будут полезными. Между тем, вот каталог ошибок или других раздражающих вещей, которые я нашел в коде для новичков. Некоторое совпадение с страницей стиля Cal Tech, на которую указывает Kornel Kisielewicz. Некоторые из моих советов кажутся расплывчатыми и бесполезными, как "драгоценные камни" HaskellWiki, но я надеюсь, что, по крайней мере, это лучший совет: -)

  • Отформатируйте свой код, чтобы он соответствовал 80 столбцам. (Продвинутые пользователи могут предпочесть 87 или 88, кроме того, что это толкает его.)

  • Не забывайте, что привязки let и where создают взаимно-рекурсивное гнездо определений, а не последовательность определений.

  • Воспользуйтесь предложениями where, особенно их способностью видеть параметры функций, которые уже находятся в области видимости (славные смутные советы). Если вы действительно grokking Haskell, ваш код должен иметь гораздо больше where -связанных, чем let -обязаний. Слишком много let -связок является признаком нереконструированного программиста ML или программиста Lisp.

  • Избегайте избыточных скобок. В некоторых местах, где избыточные скобки особенно оскорбительны,

    • Вокруг условия в выражении if (маркирует вас как нереконструированного программиста C)

    • Вокруг приложения-функции, которое само является аргументом инфиксного оператора (приложение Function связывается более жестко, чем любой инфиксный оператор. Этот факт должен быть сжег в каждом мозгу Хаскеллера, во многом так же, как у нас, у динозавров, есть APL -to-left, в котором записано правило.)

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

  • Предпочитайте пространство между функцией и ее аргументом, даже если аргумент заключен в скобки.

  • Используйте оператор $ разумно, чтобы сократить круглые скобки. Помните о тесной связи между $ и infix .:

    f $ g $ h x == (f . g . h) x == f . g . h $ x
    
  • Не пропускайте встроенные типы Maybe и Either.

  • Никогда не пишите if <expression> then True else False; правильная фраза просто <expression>.

  • Не используйте head или tail, если вы можете использовать сопоставление шаблонов.

  • Не забывайте о композиции функций с оператором infix dot.

  • Используйте разрывы строк тщательно. Разрывы строк могут повысить читаемость, но есть компромисс: ваш редактор может отображать только 40-50 строк одновременно. Если вам нужно читать и понимать большую функцию одновременно, вы не должны злоупотреблять разрывами строк.

  • Почти всегда предпочитают комментарии --, которые заканчиваются на конец строки над комментариями {- ... -}. Комбинированные комментарии могут быть уместны для больших заголовков, поэтому.

  • Дайте каждой функции верхнего уровня явную подпись типа.

  • Если возможно, выровняйте строки --, = и даже скобки и запятые, которые встречаются в смежных строках.

  • Под влиянием, поскольку я являюсь центральным центром GHC, у меня очень мягкое предпочтение использовать camelCase для экспортированных идентификаторов и short_name с символами подчеркивания для локальных переменных where -bound или let.

Ответ 2

Некоторые хорошие правила thumbs imho:

  • Проконсультируйтесь с HLint, чтобы убедиться, что у вас нет избыточных брекетов, и что ваш код не является бессмысленным. /li >
  • Избегайте воссоздания существующих функций библиотеки. Hoogle может помочь вам найти их.
    • Часто существующие функции библиотеки более общие, чем то, что они собираются сделать. Например, если вы хотите Maybe (Maybe a) -> Maybe a, тогда join делает это между прочим.
  • Иногда именования и документация аргументов важны.
    • Для такой функции, как replicate :: Int -> a -> [a], довольно очевидно, что делает каждый из аргументов, только из их типов.
    • Для функции, которая принимает несколько аргументов одного и того же типа, например isPrefixOf :: (Eq a) => [a] -> [a] -> Bool, важнее имя/документация аргументов.
  • Если одна функция существует только для обслуживания другой функции и в противном случае не является полезной, и/или трудно думать о хорошем имени для нее, то она, вероятно, должна существовать в ней caller where, а не в область модуля.
  • DRY
    • При необходимости используйте шаблон-Haskell.
    • Связи функций, таких как zip3, zipWith3, zip4, zipWith4 и т.д., очень меняются. Используйте Applicative стиль с ZipList. Вам, вероятно, никогда не нужны такие функции.
    • Производить экземпляры автоматически. Пакет derive может помочь вам получить экземпляры для классов типов, таких как Functor (существует только один правильный способ сделать тип экземпляр Functor).
  • Более общий код имеет несколько преимуществ:
    • Это более полезно и многоразово.
    • Он менее подвержен ошибкам, потому что есть больше ограничений.
      • Например, если вы хотите запрограммировать concat :: [[a]] -> [a] и обратите внимание, как это может быть более общим как join :: Monad m => m (m a) -> m a. При программировании join есть меньше места для ошибок, потому что при программировании concat вы можете поменять списки по ошибке, а в join вы можете сделать очень мало.
  • При использовании одного и того же стека монадных трансформаторов во многих местах вашего кода создайте синоним типа. Это сделает типы более короткими, более краткими и более легкими для изменения в объеме.
  • Остерегайтесь "ленивого ввода-вывода". Например, readFile действительно не читает содержимое файла в момент чтения файла.
  • Избегайте отступать так сильно, что я не могу найти код.
  • Если ваш тип логически является экземпляром типа-класса, сделайте его экземпляром.
    • Экземпляр может заменить другие функции интерфейса, которые вы, возможно, рассмотрели со знакомыми.
    • Примечание. Если существует более одного логического экземпляра, создайте newtype-wrappers для экземпляров.
    • Сделайте разные экземпляры согласованными. Было бы очень сложно/плохо, если список Applicative вел себя как ZipList.

Ответ 4

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

    func = boo . boppity . bippity . snd
        where boo = ...
              boppity = ...
              bippity = ...
    
  • Мне нравится использовать ($) только во избежание вложенных парсеров или длинных выражений в скобках

  • ... Я думал, что у меня есть еще кое-что во мне, о хорошо

Ответ 5

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