Home > Blockchain >  Haskell Listing the first 10 numbers starting from 1 which are divisible by all the numbers from 2 t
Haskell Listing the first 10 numbers starting from 1 which are divisible by all the numbers from 2 t

Time:11-09

--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 use filter 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 number y. Now for something new: you want to abstract that as a predicate on x, and you want to parameterize that predicate by y. 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 using fmap divisibleBy. (Or map, 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 suggest all ($ 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.

  • Related