Reputation: 391
I am trying to write a function that efficiently tells me when items in a list are divisible or not by all items in a range. The problem is, I don't know to stop the list comprehension immediately when a false is encountered.
allDivisByRng n start stop =
[n `mod` x == 0 | x <- [start, start+1 .. stop]]
I have tried takeWhile
but can't get that to do what I want. Please advise.
allDivisByRng n start stop =
takeWhile( == True ) [ n `mod` x == 0 | x <- [start, start+1.. stop] ]
When I run allDivisByRng 10 2 4
I get a list of trues
Some other sample runs
*Main> allDivisByRng 12 2 10
[True,True,True]
*Main> allDivisByRng 12 2 150
[True,True,True]
-- I want this to return false
*Main> allDivisByRng 2520 2 10
[True,True,True,True,True,True,True,True,True]
-- I want this to return True
I have also tried searching for False
allDivisByRng n start stop =
takeWhile( == False ) [ n `mod` x == 0 | x <- [start, start+1.. stop] ]
*Main> allDivisByRng 10 2 3
[]
-- want false to be returned
*Main> allDivisByRng 10 2 10
[]
-- want false to be returned
*Main> allDivisByRng 2520 2 10
[]
-- want true to be returned
*Main> allDivisByRng 12 2 10
[]
-- want false to be returned
Upvotes: 0
Views: 508
Reputation: 1783
There is no need of "stopping a list comprehension" in Haskell. By default, evaluation is lazy. This means values aren't really computed until they are actually needed.
This allows us to work with infinite data structures:
take 10 [1..]
--> [1,2,3,4,5,6,7,8,9,10]
Or with structures that have invalid values in them:
take 1 ["It works!", error "Exception thrown"]
--> "It works!"
So we just need to process the list to a function that reduces the list of booleans to a single bool.
Hoogle is a nifty little tool to search for functions that match a given type signature. I'd recommend you get acquainted with it, because more often that not you'll find exactly what you're looking for.
In this case, searching for [Bool] -> Bool
(a function that reduces a list of booleans to a single bool) gives us the following function defined in the Prelude (no imports needed):
and :: Foldable t => t Bool -> Bool
See if you can apply it to get what you want!
There happens to be another function that is a bit closed to what we want: test if all elements in a list satisfy a predicate. With this "all
" fuction, we can rewrite your function in a very legible way (imo):
allDivisByRng n start stop =
all (n `isDividedBy`) [start .. stop]
where
n `isDividedBy` x = n `mod` x == 0
Upvotes: 2
Reputation: 13913
The function all
,
all :: Foldable t => (a -> Bool) -> t a -> Bool
allows you to check whether all elements of a foldable structure satisfy a certain condition. In your case,
allDivisByRng n start stop = all ((== 0) . (mod n)) [start..stop]
Upvotes: 5