Project Euler: A (much) better way to solve problem #5? - haskell

You probably know about project Euler question 5: get the smallest number divisble by all numbers 1 to 20.
The logic I applied was "start with the first number greater than the largest of the list(20) and also divisible by it which is 40" and stepsize of 20 (largest number)
I did this using list comprehension but it's pretty lame.
pe5 = head [x|x<-[40,60..],x`mod`3==0,x`mod`4==0,x`mod`6==0,x`mod`7==0,x`mod`8==0,x`mod`9==0,x`mod`11==0,x`mod`12==0,x`mod`13==0,x`mod`14==0,x`mod`15==0,x`mod`16==0,x`mod`17==0,x`mod`18==0,x`mod`19==0]
Can we do this better perhaps using zipWith and filter maybe?
Just to clarify, this is not a homework assignment. I'm doing this to wrap my brain around Haskell. (So far I'm losing!)
:Thanx all
I think this is a saner way (there may be thousand more better ways but this would suffice) to do it
listlcm'::(Integral a)=> [a] -> a
listlcm' [x] = x
listlcm' (x:xs) = lcm x (listlcm' xs)

In this particular case, you can get it for free using foldl and lcm:
euler = foldl lcm 2 [3..20]
This gives me 232792560 instantaneously.

Since the spoiler has already been posted, I thought I'd explain how it works.
The smallest number divisible by two numbers is also known as the least common multiple of those numbers. There is a function for calculating this in the Prelude.
λ> lcm 10 12
60
Now, to extend this to multiple numbers we exploit the following property
lcm(a1, ... an) = lcm(lcm(a1, ... an-1), an)
In Haskell, f(f(... f(a1, a2), ...), an) can be written foldl1 f [a1, a2, ... an], so we can solve the problem with this simple one-liner:
λ> foldl1 lcm [1..20]
232792560
This finds the solution in a fraction of a second.

Yes, you can do much better. For starters, rewrite to something like
head [x | x<-[40,60..], all (\y -> x`mod`y == 0) [2..20] ]
But what you really need here is not slicker Haskell, but a smarter algorithm. Hint: use the Fundamental Theorem of Arithmetic. Your Haskell solution would then start with the standard sieve-of-Eratosthenes example.

Since this is a exercise in learning Haskell, I will only point out that there is a more efficient way to solve this problem mathematically but I will let you figure that out on your own. Instead, let's solve the problem in Haskell using your logic.
I simplified it a little bit:
head [x | x <- [20,40..], length( filter ( \y -> x `mod` y /= 0) [1..20]) == 0]
This creates a filter on the divisors list, and when its length is 0, it means all the divisors divide our x, so that must be our number. This reduces some of the clutter you had in your example. Note that this method is VERY slow; can you think of a better mathematical way to tackle this? Start looking at prime factorizations...

Related

Haskell - Filtering Odds in function that shows powers of 2

I have this developed function that shows the powers of 2 from the range you choose:
import Data.Bits(Bits, (.&.))
isPower2 :: (Bits i, Integral i) => i -> Bool
isPower2 n = n .&. (n-1) == 0
This works well but i need to filter only the powers of 2 from odds numbers of the range choosed, for example :
filter isPower2 [0 .. 1000]
[0,1,2,4,8,16,32,64,128,256,512]
This input and output above shows all the powers between 0 and 1000 but what i need is only the powers from odds, so my output that i need is:
[2,8,32,128,512]
Is there a way to filter this function pointing only to odds numbers? Thanks.
I'd recommend first writing a function that checks whether a power of two is odd power of two.
power2isOddPower2 :: (Bits i, Integral i) => i -> Bool
Maybe first think how to do this for the concrete case Word8, then generalize it to arbitrary positive integers.
Then you can combine this to a predicate that checks whether an arbitrary number is an odd power of two, and use that for the filtering:
filter (\n -> isPower2 n && power2isOddPower2 n) [0 .. 1000]
That's a clever algorithm for checking whether a number is a power of 2. But unfortunately, it's not well suited to this kind of further analysis. So I'm going to propose a slightly different technique. Let's split the problem into pieces. Haskell has a power function called (^) (actually, it has three that are subtly different, but for our purposes the simplest one will do just fine). So let's start by getting all of the powers of two. Yes, all of them.
> map (2 ^) [0..]
[1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,...]
That's an infinite list, which Haskell has no problem with. If you run it in GHCi, you'll need to hit Ctrl+C to stop it from outputting forever.
Now we want to take the ones smaller than some limit.
> takeWhile (< 1000) $ map (2 ^) [0..]
[1,2,4,8,16,32,64,128,256,512]
takeWhile is a function which, as the name implies, stops once the condition is false. It's like filter, but once it encounters one false value, it stops completely (filter will never terminate on infinite lists, because it insists on checking every value).
So now we have a way to get the list you have in the OP. But we started with the powers ([0..]). So if we want to filter some powers, we can add a filter to the right-hand side
> takeWhile (< 1000) . map (2 ^) . filter (\x -> x `mod` 2 == 1) $ [0..]
[2,8,32,128,512]
Of course, we would want to split this into a few helper functions (isOdd, for instance, is pretty easy to factor out into a where clause), as it's getting a bit long on its own. But that's the basic idea.

infinite lists, lazy evaluation and length

Haskell noob here: I'm still trying to understand the mechanics of the language, so if my question is plain stupid, forgive me and point me to some link which I can learn from (I've searched awhile in similar topics here on stackoverflow, but still I can't get this).
I came out with this function:
chunks :: Int -> [a] -> [[a]]
chunks n xs
| length xs <= n = [xs]
| otherwise = let (ch, rest) = splitAt n xs in ch:chunks n rest
so that
ghci> chunks 4 "abracadabra"
["abra","cada","bra"]
ghci>
ghci> chunks 3 [1..6]
[[1,2,3],[4,5,6]]
I was pretty satisfied with that, then I thought "there's lazy evaluation! I can use this even on an infinite sequence!". So i tried take 4 $ chunks 3 [1..]. I was hoping that the lazy haskell magic would have produced [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], instead it seems like this time lazyness can't help me: it can't reach the end of the computation (is it walking all the way long to the end of [1..]?)
I think the problem is in the "length xs" part: ghci seems to get stuck also on a simple length [1..]. So I'm asking: is length actually iterating the whole list to give a response? If so, I guess length is to be avoided every time I try to implement something working well with the lazy evaluation, so there is some alternative?
(for instance, how can I improve my example to work with infinite lists?)
is length actually iterating the whole list to give a response?
Yes.
I guess length is to be avoided every time I try to implement something working well with the lazy evaluation
Not just that, it also gives you bad runtimes when laziness isn't a factor (being O(n) in cases where an O(1) check often suffices1), so you should avoid it most of the time in general.
how can I improve my example to work with infinite lists?
You don't need to check whether the length of the list is less than n, you just need to check whether it's zero. And that you can do with a simple pattern match.
1 For example something like f xs | length xs >= 2 = ..., which is O(n), can be replaced with f (x1 : x2 : xs) = ..., which is O(1).
Another trick you can do (which I've seen in Data.Text, but am surprised is not in Prelude for lists in general) is to make length short-circuit as soon as possible by returning an Ordering rather than a Bool.
compareLength :: [a] -> Int -> Ordering
compareLength [] n = compare 0 n
compareLength _ 0 = GT
compareLength (x : xs) n = compareLength xs (n - 1)
Then you can use it in chunks.
chunks :: Int -> [a] -> [[a]]
chunks n xs = case compareLength xs n of
LT -> [xs]
_ -> let (ch, rest) = splitAt n xs in ch:chunks n rest
And this works fine.
*Main> take 4 $ chunks 3 [1..]
[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
For this particular case, other implementations might be more idiomatic, but hopefully this is a nice trick to know.
is length actually iterating the whole list to give a response?
Yes, absolutely.
length is to be avoided every time I try to implement something working well with the lazy evaluation
Yes, absolutely.
so there is some alternative?
Yes: solve the problem without referencing length. There are no general methods of problem solving so you need to work out each specific case.
how can I improve my example to work with infinite lists
You are a railroad worker. A huge train if cars begins where you are standing and stretches over the horizon. You have no idea where it ends, if ever. Your job is to separate it into small trains of three cars each. How do you proceed?

Prime Factoring Function in Haskell

I am trying to make a function that will display a number's prime factors with a list (infinite) that I give it. Here is what I have so far:
-- Here is a much more efficient (but harder to understand) version of primes.
-- Try "take 100 primes" as an example (or even more if you like)
primes = 2 : primesFrom3 where
primesFrom3 = sieve [3,5..] 9 primesFrom3
sieve (x:xs) b ~ps#(p:q:_)
| x < b = x : sieve xs b ps
| otherwise = sieve [x | x <- xs, rem x p /= 0] (q^2) (tail ps)
-- Write a function that factors its first argument using the (infinite)
-- list of available factors given in its second argument
-- (using rem x p /= 0 to check divisibility)
primeFactsWith :: Integer -> [Integer] -> [Integer]
primeFactsWith n (p:ps) = if (rem n p /= 0) then
(primeFactsWith n ps)
else (primeFactsWith p ps)
The top half was not written by me and works just fine. I am trying to get the second half to work, but it isn't. Read the comments in the code to better understand exactly what I am trying to do. Thanks! Oh and please don't just spout the answer. Give me some hints on how to do it and maybe what is wrong.
What's wrong
The problem is that you do a recursive call in both branches, therefore the function will never stop.
Some Hints
To build a recursive list-producing function, you'll need two branches or cases:
Base case no recursive call, this stops the recursion and returns the final part of the result.
Recursive case here you modify the parameters of the function and call it again with the modified parameters, possibly also returning a part of the result.
You need two sub branches at the recursive branch. One if you've found a prime factor, and another if the current number is no prime factor.
Here is a skeleton, you need to fill in the parts in the <> brackets.
primeFactsWith :: Integer -> [Integer] -> [Integer]
primeFactsWith n (p:ps) = if <halt condition> then
<final result>
else if (rem n p /= 0) then
<not a factor - recursive call 1>
else
<found a factor - return it,
and make recursive call 2>
If you have found a prime factor, you can divide the number by it, to get a smaller number, without that factor. To perform integer division Haskell provides a function named div.
If you reach the number 1, you have generated all prime factors and you can stop. The final part of a prime factors list, that comes after all its factors, is an empty list.
You can drop any prime from your infinite list if you no longer need it, but be aware that a number could contain a prime several times in the factors list. If you want to drop p you can just use ps, from the pattern; if you want to keep p you must use (p:ps).
The cons operator (:) can be used to build a list. You can use it to return one number of the result list, and use a recursive call to find the remaining numbers, e.g.
x : foo y z
I hope that helps, if you have any questions don't hesitate to ask.
Here's a hint.
So you're recursing, which is good.
In one branch you keep looking for factors of n. In the other branch you seem to look for the factors of p, which is a bit weird, but whatevs.
Where do you return the factors of n you've found?

Is it possible to create a list of fibonacci numbers using [edit: a very limited set of knowledge]?

For instance, in the form of something like this:
let f = [ a | a <- [1..], a == a - 1]
I'm just curious. It seems like it'd be possible, but I can't quite wrap my head around how it would work. This question is meant more for understanding how Haskell works, not so much because I'm looking for a practical application.
Also, I know that similar questions have been asked, but none of the posts I looked at offered any help in doing it they way I'm curious about.
Edit: sorry for the vagueness. Let me clarify a new rule, then. The challenge is to find a way to represent an infinite list of fibonacci numbers using as little extra from the first chapter of Learn You A Haskell For Great Good! as possible. How's that? In other words, what's the most creative way you can think of to produce those numbers with as little 'knowledge' as possible. Sorry for making anyones answer invalid, now.
Try this:
import Data.List (tails)
fib :: [Integer]
fib = 0 : 1 : [ a + b | (a:b:_) <- tails fib ]
Yes it makes use of the cons operator (:) for the seed values. However I believe that can be pardoned.
It is certainly possible with a nasty trick: there's a closed form of the Fibonacci sequence
fn = (φn - ψn) / √5
so
Prelude> let (φ, ψ) = (1/2+s, 1/2-s) where s = sqrt(5/4)
Prelude> let fibs = [ round $ (φ^n - ψ^n) / sqrt 5 | n <- [0..] ]
Prelude> take 20 fibs
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181]
This works in floating point, so it's extremely fast but fails to work exactly at high values:
Prelude> take 3 $ drop 80 fibs
[23416728348467676,37889062373143896,61305790721611584]
Prelude> 23416728348467676 + 37889062373143896 - 61305790721611584
-12
I think it can not work without exploiting irrational numbers or putting some recursion in the comprehension, because list comprehensions are just syntactic sugar for monadic binds and those by themselves aren't Turing-complete, so they can't generate an infinite sequence constructively.
The simplest is of course:
fibs = f 0 1 where f a b = a : (f b (a+b))
We arrive at this solution from the definition.
Let f a b computes a stream of numbers starting with a and followed by b. Then we can use f to compute the substream of numbers following b, if we can compute the number following immediately after b. We know that immediately after b follows a+b, so we get that stream and append it to a.
This solution does not involve any list library functions, using list comprehensions instead.
fib = [ x | (x,_) <- l ]
where l = (0,1) : [ (b,a+b) | (a,b) <- l ]

Interesting puzzle in Haskell

Hello studying Haskell I came up at an exercise at the web that it requested to create a list given an integer the way described below:
for example if integer was 3 then a list should be generated that it contains the following:
[[3],[1,2],[2,1],[1,1,1]]
note
3=3
1+2=3
2+1=3
1+1+1=3
if integer was 2 then it would be:
[[2],[1,1]]
I cannot think a way of implementing this, so can you provide me with any hints? I believe that I must use list comprehension but I cannot think anything further than this
Always start with a type signature:
sums :: Int -> [[Int]]
Now, let's think about the recursion.
What is the base case? Can you think of a number for which the answer is trivial?
Let's say you've implemented your function and it works for all numbers under 10, so sums 9 for example returns the right answer. How would you implement sums 10?
Don't bother yourself with implementation details (e.g. List comprehension vs. filter and map) until you've answered these questions.
And another tip: Haskell programmers love to show off and create tiny-pointfree functions, but don't let it confuse you. Getting things to work is the important thing. It's better to have a working yet somewhat "ugly" solution than to stare at the screen looking for an elegant one.
Good luck!
Looks a bit like partitioning a list. A bit of googling turns up this
http://www.haskell.org/pipermail/beginners/2011-April/006832.html
partitions [] = [[]]
partitions (x:xs) = [[x]:p | p <- partitions xs]
++ [(x:ys):yss | (ys:yss) <- partitions xs]
which produces something like this
*Main> partitions "abc"
[["a","b","c"],["a","bc"],["ab","c"],["abc"]]
now all you have to do is get the length of the inner lists
map (map length) (partitions "abc")
[[1,1,1],[1,2],[2,1],[3]]
you can also change partitions to give you the result directly
partitions' 0 = [[]]
partitions' n = [1:p | p <- partitions' (n-1)]
++ [(1+ys):yss | (ys:yss) <- partitions' (n-1)]

Resources