Хороший Haskell, кодирующий стандарты

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

74
задан Alexey Romanov 30 December 2009 в 23:23
поделиться

4 ответа

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

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

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

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

  • -избегайте лишних скобок. Некоторые места, где лишние скобки особенно обидны, это

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

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

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

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

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

    f $ g $ h x == (f . g . h) x == f . g . h $ x
    
  • Не упускайте из виду встроенные Может быть и типы .

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

  • Не используйте голову или хвост , когда можно использовать совпадение паттернов.

  • Не упускайте из виду состав функции с оператором точки прикрепления.

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

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

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

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

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

91
ответ дан 24 November 2019 в 11:59
поделиться

Я бы посоветовал взглянуть на эту проверку стиля .

.
6
ответ дан 24 November 2019 в 11:59
поделиться
  • Мне нравится пытаться организовать функции. такие же бесточечные стилевые композиции, как насколько это возможно, делая вещи например:

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

  • .... Я думал, что во мне есть еще несколько, о ну

6
ответ дан 24 November 2019 в 11:59
поделиться

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

  • Проконсультируйтесь с HLint, чтобы убедиться, что у вас нет лишних скобок и что ваш код не бессмысленно точечно заполнен.
  • Избегайте воссоздания существующих библиотечных функций. Hoogle может помочь вам найти их.
    • Часто существующие библиотечные функции являются более общими, чем то, что вы собирались сделать. Например, если вы хотите, чтобы -> Может быть, a, тогда join делает это, кроме всего прочего.
  • Иногда важным является именование аргументов и документация.
    • Для функции типа повторить :: Int -> a -> [a] довольно очевидно, что делает каждый из аргументов, только из их типов.
    • Для функции, которая принимает несколько аргументов одного типа, например isPrefixOf :: (Eq a) => [a] -> [a] -> Bool, более важным является именование/документирование аргументов.
  • Если одна функция существует только для обслуживания другой функции, и в противном случае она не является полезной, и/или трудно придумать для неё хорошее имя, то, вероятно, она должна существовать в пункте вызова , где, а не в области действия модуля.
  • DRY.
    • При необходимости используйте шаблон Хаскелл.
    • Комплекты функций типа zip3, zipWith3, zip4, zipWith4 и т.д. и т.п. очень эффективны. Вместо этого используйте Applicative с ZipLists. Вероятно, вам никогда не понадобятся такие функции, как эти.
    • Автоматически создавайте экземпляры. Пакет derive может помочь вам получить экземпляры для таких классов типа как Functor (есть только один правильный способ сделать тип экземпляром Functor).
  • Код, который является более общим, имеет несколько преимуществ:
    • Он более полезен и может быть использован многократно.
    • Он менее подвержен ошибкам, так как имеет больше ограничений.
      • Например, если вы хотите запрограммировать concat :: [[a]]. -> [a] , и обратите внимание на то, как это может быть более общим, так как присоединяется :: Monad m => m (m a) -> m a. При программировании join меньше места для ошибок, т.к. при программировании concat можно по ошибке перевернуть списки, а в join сделать очень мало.
  • При использовании одного и того же стека трансформаторов monad во многих местах Вашего кода, сделайте для него синоним типа. Это сделает типы короче, лаконичнее и легче модифицировать массово.
  • Остерегайтесь "ленивого ввода-вывода". Например, readFile на самом деле не читает содержимое файла в момент чтения файла.
  • Избегайте отступов настолько, что я не могу найти код.
  • Если ваш тип логически является экземпляром класса типа, то сделайте его экземпляром.
    • Экземпляр может заменить другие интерфейсные функции, которые вы, возможно, уже рассмотрели, на знакомые.
    • Замечание: Если существует более одного логического экземпляра, создайте для экземпляров обертку нового типа.
    • Сделайте различные экземпляры согласованными. Было бы очень запутано/ошибочно, если бы список Applicative вел себя как ZipList.
27
ответ дан 24 November 2019 в 11:59
поделиться
Другие вопросы по тегам:

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