Разница между двумя функциями, создающими одноэлементный список

При запуске hlint над моей программой сообщалось об ошибке для

\x -> [x]

и предложил альтернативную форму

(: [])

Что там ошибочно согласно подсказке о первой форме, и, следовательно, почему я должен использовать (менее читаемый) второй вариант?

редактировать

(явно добавил подсказку к вопросу)

Мой вопрос не столько в том, в чем разница (я понимаю их обоих) с лексической точки зрения. Моя проблема в том, что я не понимаю, почему hlint помечает это как ошибку. Есть ли, например, разница в лени? Кроме того, почему предыдущая мысль ошибочной \x -> Just x вызывает только предупреждение.

3 ответа

Решение

Обычный вопрос, на который я только что добавил ответ в руководстве по HLint. Это говорит:

Каждый намек имеет уровень серьезности:

  • Ошибка - например concat (map f x) предполагает concatMap f x как подсказка серьезности "ошибки". С точки зрения стиля, вы всегда должны заменить комбинацию concat а также map с concatMap, Обратите внимание, что оба выражения эквивалентны - HLint сообщает об ошибке стиля, а не фактической ошибке в коде.
  • Предупреждение - например x !! 0 предполагает head x в качестве "предупреждения" указывается серьезность. типично head это более простой способ выражения первого элемента списка, особенно если вы относитесь к списку индуктивно. Однако в выражении f (x !! 4) (x !! 0) (x !! 7)замена среднего аргумента на голову усложняет следование шаблону и, вероятно, является плохой идеей. Предупреждающие подсказки часто имеют смысл, но их не следует применять вслепую.

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

Хотя разница в личном вкусе, иногда я передумал. Глядя на два примера в этой теме, (:[]) кажется довольно "сложным" намеком - вы ломаете синтаксический сахар [x] в x:[], который в некотором роде очищает абстракцию списка как универсального контейнера, если вы никогда не сопоставляете шаблон с ним. По сравнению \x -> Just x в Just всегда кажется хорошей идеей. Поэтому в HLint-1.8.43 (только что выпущенном) я сделал первое предупреждение, а второе ошибку.

Там нет никакой разницы. HLint занимается вопросами стиля; в конечном счете, это всего лишь подсказки о том, как сделать ваш код лучше.

В общем, использование лямбды с конструктором или подобной функцией является избыточным и затрудняет чтение кода. В качестве крайнего примера возьмем конструктор, как Just как пример: сравнить Just в \ x -> Just x, Это эквивалентно, но вторая версия, безусловно, делает вещи более запутанными! В качестве более близкого примера, большинство людей выбрали бы (+ 1) над \ x -> x + 1,

В вашем конкретном случае это другая история, потому что списки имеют специальный синтаксис. Так что если вам нравится \ x -> [x] Версия лучше, просто держи ее. Однако, как только вы привыкнете к разделам оператора, скорее всего, вы найдете (: []) версию так же легко - если не проще - читать, так что рассмотрите возможность ее использования даже сейчас.

Я мог бы рассмотреть возможность использования return или же pure за это:

ghci> return 0 :: [Int]
[0]

ghci> import Control.Applicative
ghci> pure 0 :: [Int]
[0]

Мне нужно было включить аннотацию типа (:: [Int]) потому что я работал в GHCi. В середине другого кода вам, вероятно, это не понадобится.

Другие вопросы по тегам