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

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


person Alexey Romanov    schedule 30.12.2009    source источник
comment
// Но разве это не вопрос мнения?   -  person Nathan Basanese    schedule 11.06.2015


Ответы (5)


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

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

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

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

  • Избегайте лишних скобок. Некоторые места, где лишние круглые скобки особенно оскорбительны:

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

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

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

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

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

    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 или let.

person Norman Ramsey    schedule 31.12.2009
comment
Мне очень нравится этот ответ, но не могли бы вы предоставить еще несколько примеров кода? Я все еще не полностью знаком с жаргоном Haskell, поэтому приложение Function связывает более жестко, чем любой инфиксный оператор, и несколько других моментов меня смущают. - person CaptainCasey; 05.01.2010
comment
@CaptainCasey: Я начал добавлять несколько примеров, но потом ответ стал слишком длинным и трудным для чтения. Это краткий набор предложений; если он превратится в настоящее руководство по стилю, его должен будет сделать кто-то другой. Но дайте мне знать ваши конкретные моменты. Плотность привязки просто означает, что (length l) + 1 некрасиво. Приложение length автоматически связывает более жестко, чем приложение +, поэтому идиоматическая вещь для написания - length l + 1. Скобки - проклятие функциональных программ. - person Norman Ramsey; 06.01.2010
comment
about: Format your code so it fits in 80 columns. Я больше предпочитаю 120 цветов .. Кажется, ничто не помещается в 80. - person Talvi Watia; 09.07.2010
comment
Прочитав большинство ваших ответов на Haskell, я могу с уверенностью сказать, что вы отличный профессор! - person fedvasu; 06.12.2011
comment
Ваши рекомендации по стилю полезны, но все же я хотел бы знать, что вы думаете о коде со многими странными операторами, такими как = ??, $$, ‹==›, которые, похоже, нравятся многим хаскеллерам? Это хороший стиль? Мне очень трудно понять затронутый исходный код. - person mljrg; 17.10.2015

Несколько хороших правил большого пальца imho:

  • Проконсультируйтесь с HLint, чтобы убедиться, что у вас нет лишних скобок и что ваш код не лишен смысла. точка-полная.
  • Avoid recreating existing library functions. Hoogle can help you find them.
    • Often times existing library functions are more general than what one was going to make. For example if you want Maybe (Maybe a) -> Maybe a, then join does that among other things.
  • Argument naming and documentation is important sometimes.
    • For a function like replicate :: Int -> a -> [a], it's pretty obvious what each of the arguments does, from their types alone.
    • Для функции, которая принимает несколько аргументов одного типа, например isPrefixOf :: (Eq a) => [a] -> [a] -> Bool, наименование / документирование аргументов более важно.
  • Если одна функция существует только для обслуживания другой функции и в остальном бесполезна и / или трудно придумать для нее хорошее имя, то она, вероятно, должна существовать в предложении where вызывающего объекта, а не в области видимости модуля.
  • DRY
    • Use Template-Haskell when appropriate.
    • Связки функций типа zip3, zipWith3, zip4, zipWith4 и т. Д. Очень удобны. Вместо этого используйте стиль Applicative с ZipLists. Вероятно, вам никогда не понадобятся такие функции.
    • Создавать экземпляры автоматически. Пакет derive может помочь вам получить экземпляры для классов типов, таких как Functor (есть только один правильный способ сделать тип экземпляром Functor).
  • Code that is more general has several benefits:
    • It's more useful and reusable.
    • It is less prone to bugs because there are more constraints.
      • For example if you want to program concat :: [[a]] -> [a], and notice how it can be more general as join :: Monad m => m (m a) -> m a. There is less room for error when programming join because when programming concat you can reverse the lists by mistake and in join there are very few things you can do.
  • При использовании одного и того же стека преобразователей монад во многих местах кода сделайте для него синоним типа. Это сделает типы короче, лаконичнее и их будет легче массово изменять.
  • Остерегайтесь "ленивого ввода-вывода". Например, readFile на самом деле не читает содержимое файла в момент чтения файла.
  • Избегайте слишком большого отступа, чтобы я не мог найти код.
  • If your type is logically an instance of a type-class, make it an instance.
    • The instance can replace other interface functions you may have considered with familiar ones.
    • Примечание. Если существует более одного логического экземпляра, создайте для них обертки newtype.
    • Сделайте разные экземпляры последовательными. Было бы очень запутанно / плохо, если бы список Applicative вел себя как ZipList.
person yairchu    schedule 06.01.2010

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

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

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

person jberryman    schedule 31.12.2009


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

person d12frosted    schedule 26.12.2013