--for number divisible by 15 we can get it easily
take 10 [x | x <- [1..] , x `mod` 15 == 0 ]
--but for all how do I use the all option
take 10 [x | x <- [1..] , x `mod` [2..15] == 0 ]
take 10 [x | x <- [1..] , all x `mod` [2..15] == 0 ]
I want to understand how to use all in this particular case.
I have read Haskell documentation but I am new to this language coming from Python so I am unable to figure the logic.
CodePudding user response:
First you can have a function to check if a number is mod by all [2..15].
modByNumbers x ns = all (\n -> x `mod` n == 0) ns
Then you can use it like the mod
function:
take 10 [x | x <- [1..] , x `modByNumbers` [2..15] ]
CodePudding user response:
Alternatively, using math, we know that the smallest number divible by all numbers less than n
is the product of all of the prime numbers x
less than n
raised to the floor of the result of logBase x n
.
A basic isPrime
function:
isPrime n = length [ x | x <- [2..n], n `mod` x == 0] == 1
Using that to get all of the primes less than 15
:
p = [fromIntegral x :: Float | x <- [2..15], isPrime x]
-- [2.0,3.0,5.0,7.0,11.0,13.0]
Now we can get the exponents:
e = [fromIntegral (floor $ logBase x 15) :: Float | x <- p']
-- [3.0,2.0,1.0,1.0,1.0,1.0]
If we zip these together.
z = zipWith (**) p e
-- [8.0,9.0,5.0,7.0,11.0,13.0]
And then find the product of these we get the smallest number divisible by all numbers between 2 and 15.
smallest = product z
-- 360360.0
And now to get the rest we just need to multiply that by the numbers from 1 to 15.
map round $ take 10 [smallest * x | x <- [1..15]]
-- [360360,720720,1081080,1441440,1801800,2162160,2522520,2882880,3243240,3603600]
This has the advantage of running substantially faster.
CodePudding user response:
Decompose the problem.
- You already know how to take the first 10 elements of a list, so set that aside and forget about it. There are infinitely many numbers divisible by all of [2,15], your remaining task is to list them all.
- There are infinitely many natural numbers (unconstrained), and you already know how to list them all (
[1..]
), so your remaining task is to transform that list into the "sub-list" who's elements are divisible by all of [2,15]. - You already know how to transform a list into the "sub-list" satisfying some constraint (
predicate :: X -> Bool
). You're using a list comprehension in your posted code, but I think the rest of this is going to be easier if you usefilter
instead. Either way, your remaining task is to represent "is divisible by all of [2,15]" as a predicate.. - You already know how to check if a number
x
is divisible by another numbery
. Now for something new: you want to abstract that as a predicate onx
, and you want to parameterize that predicate byy
. I'm sure you could get this part on your own if asked:
divisibleBy :: Int -> (Int -> Bool)
divisibleBy y x = 0 == (x `mod` y)
You already know how to represent [2,15] as[2..15]
; we can turn that into a list of predicates usingfmap divisibleBy
. (Ormap
, worry about that difference tomorrow.) Your remaining task is to turn a list of predicates into a predicate. - You have a couple of options, but you already found
all :: (a -> Bool) -> [a] -> Bool
, so I'll suggestall ($ x)
. (note)
Once you've put all these pieces together into something that works, you'll probably be able to boil it back down into something that looks a little bit like what you first wrote.