Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A better way than counting the length of a list of units

I sometimes find myself writing code like this:

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

Or equivalently:

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

Is there a better way to perform this sort of computation? More efficient? More readable? More idiomatic?

like image 782
Dan Burton Avatar asked Jan 18 '12 02:01

Dan Burton


2 Answers

Primo

guard someGuard
return ()

is redundant, guard already returns () if the condition is true. Then I suppose someGuard actually depends on x, otherwise it would be if someGuard then length someList else 0. The usual way to write it is

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

if the situation is really as simple as your example looks. For more complicated situations, using one of your example styles is the most direct way. I find the do-notation preferable if things get really complicated.

like image 149
Daniel Fischer Avatar answered Sep 22 '22 01:09

Daniel Fischer


If you find yourself repeatedly programming to a pattern, the thing to do is write a higher-order function to encapsulate that pattern. You could use the body you have, but in order to be utterly confident that your code is not allocating, I would recommend to use foldl and strict application of an increment operator:

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

I have used QuickCheck to confirm this code equivalent to your original code. (And yes, it is pretty cool that QuickCheck will test with random predicates.)

like image 38
Norman Ramsey Avatar answered Sep 19 '22 01:09

Norman Ramsey