Разница между двумя функциями, создающими единый список
При запуске hlint над моей программой сообщалось ошибка для
\x -> [x]
и предложил альтернативную форму
(: [])
Что существует ошибочно в соответствии с hlint о первой форме и, следовательно, почему я должен использовать (менее читаемый) второй вариант?
Изменить
(добавлено hlint явно на вопрос)
Мой вопрос кроется не столько в том, какова разница (я понимаю их обоих) в лексической точке зрения. Моя проблема заключается в том, что я не понимаю, почему hlint отмечает это как ошибку. Есть ли, например, разница в лень? Кроме того, почему предыдущая мысль считается ошибочной по hlint, а \x -> Just x
вызывает только предупреждение.
Ответы
Ответ 1
Общий вопрос, на который я только что добавил ответ в Руководство 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, вы можете сосредоточиться на подсказках ошибок до предупреждений.
В то время как разница - личный вкус, иногда я перехожу на ум. Рассматривая два примера в этом потоке, (:[])
кажется относительно "сложным" намеком - вы разрушаете синтаксический сахар от [x]
до x:[]
, который каким-то образом просматривает абстракцию списка как общий контейнер, если вы никогда не сопоставляете ему шаблон. Напротив, \x -> Just x
to Just
всегда кажется хорошей идеей. Поэтому в HLint-1.8.43 (только что выпущен) я сделал первое предупреждение, а второе - ошибкой.
Ответ 2
Нет никакой реальной разницы. HLint относится к проблемам стиля; в конечном счете, они просто намекают на то, как заставить ваш код выглядеть лучше.
В общем случае использование лямбда с конструктором или функцией вроде этого избыточно и делает код более трудным для чтения. В качестве крайнего примера возьмите конструктор типа Just
в качестве примера: сравните Just
с \ x -> Just x
. Они эквивалентны, но вторая версия, безусловно, делает вещи более запутанными! В качестве более близкого примера большинство людей выбрали бы (+ 1)
более \ x -> x + 1
.
В вашем конкретном случае это другая история, потому что списки имеют специальный синтаксис. Поэтому, если вам нравится версия \ x -> [x]
лучше, просто сохраните ее. Однако, как только вы привыкнете к разделам оператора, вероятно, вы найдете версию (: [])
такой же простой, если не простой, для чтения, поэтому подумайте об использовании ее даже сейчас.
Ответ 3
Я мог бы использовать return
или pure
для этого:
ghci> return 0 :: [Int]
[0]
ghci> import Control.Applicative
ghci> pure 0 :: [Int]
[0]
Мне нужно было включить аннотацию типа (:: [Int]
), потому что я работал в GHCi. В середине кучи другого кода вам, вероятно, не понадобится.