Лучший способ, чем подсчет длины списка единиц - PullRequest
6 голосов
/ 18 января 2012

Иногда я пишу такой код:

someFunc :: Foo -> Int
someFunc foo = length $ do
  x <- someList
  guard someGuard
  return ()

Или эквивалентно:

someFunc foo = length [() | x <- someList, someGuard]

Есть ли лучший способ выполнить такого рода вычисления? Более эффективным? Более читабельным? Более идиоматичный?

Ответы [ 2 ]

8 голосов
/ 18 января 2012

Primo

guard someGuard
return ()

является избыточным, guard уже возвращает (), если условие истинно.Тогда я полагаю, что someGuard на самом деле зависит от x, иначе это будет if someGuard then length someList else 0.Обычный способ написать это -

someFunc foo = filter (\x -> someGuard) someList

, если ситуация действительно так проста, как выглядит ваш пример.Для более сложных ситуаций использование одного из ваших примеров стилей является наиболее прямым способом.Я считаю, что делать нотацию предпочтительнее, если все становится действительно сложно.

6 голосов
/ 18 января 2012

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

numberSatisfying :: Integral n => (a -> Bool) -> [a] -> n
numberSatisfying p = foldl (\n x -> if p x then (+1) $! n else n) 0

Я использовал QuickCheck для подтверждения этого кода, эквивалентного вашему исходному коду. (И да, очень круто, что QuickCheck будет тестировать со случайными предикатами.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...