Related
I'm trying to solve the following exercise (I'm learning Haskell):
Define x^n using a list comprehension.
And I'm struggling to find a solution.
Using recursion or fold, the solution is not complicated (for instance, foldr (*) 1 [x | c <- [1..n]]). However, using only list comprehension it gets difficult (at least for me).
In order to solve the problem, I'm trying to create a list of x^n elements and then get the length. Generating a list of x*n elements is easy, but I fail to generate a list of x^n elements.
ppower x n = length [1 | p <- [1..x], c <- [1..n]]
returns a list of x*n elements giving a wrong result. Any ideas on this will be appreciated.
A naturally-occurring exponential comes from sequence:
length (sequence [[1..x] | _ <- [1..n]])
If you haven't seen sequence yet, it's quite a general function but
when used with lists it works like:
sequence [xs1, ... , xsk] = [[x1, ... xk] | x1 <- xs1, ... , xk <- xsk]
But this is really cheating since sequence is defined recursively.
If you want to use nothing but length and list comprehensions I think
it might be impossible. The rest of this answer will be sketchy and I half
expect someone to prove me wrong. However:
We'll try to prove that such an expression can only compute values up
to some finite power of x or n, and therefore can't compute values
as big as x^n for arbitrary x and n.
Specifically we show by induction on the structure of expressions that
any expression expr has an upper bound ub(expr, m) = m^k where m
is the maximum of the free variables it uses, and k is a known finite
power which we could calculate from the structure of the expression expr.
(When we look at the whole expression, m will be max x n.)
Our upper bounds on list expressions will be bounds on both the length of the list and also bounds on any of
its elements (and lengths of its elements, etc.).
For example if we have [x..y] and we know that x <= m and y <= m, we
know that all the elements are <= m and the length is also <= m.
So we have ub([x..y], m) = m^1.
The tricky case is the list comprehension:
[eleft | x1 <- e1, ... , xk <- ek]
The result will have length equal to length e1 * ... * length ek, so
an upper bound for it would be the product of the upper bounds for
e1 to ek, or if m^i is the maximum of these then an upper bound
would be (m^i)^k = m^(i*k).
To get a bound on the elements, suppose expression eleft has ub(eleft, m') = m'^j. It can use x1
... xk. If m^i is an upper bound for these, as above, we need to
take m' = m^i and so ub(eleft, m) = (m^i)^j = m^(i*j)
As a conservative upper bound for the whole list comprehension e we
could take ub(e, m) = m^(i*j*k).
I should really also work through cases for pattern matching
(shouldn't be a problem because the parts matched are smaller than
what we already had), let definitions and functions (but we banned
recursion, so we can just fully expand these before we start), and
list literals like [x,37,x,x,n] (we can throw their lengths
into m as initially-available values).
If infinite lists like [x..] or [x,y..] are allowed they would need some
thinking about. We can construct head and filter, which means we can get
from an infinite list to its first element matching a predicate, and that looks suspiciously like a way to get recursive functions. I don't
think it's a problem since 1. they are only arithmetic sequences and
2. we'll have to construct any numbers we want to use in the
predicate. But I'm not certain here.
As #n.m suggested, I asked Richard Bird (author of the book "Introduction to functional programming", first edition, the book where I got the exercise) for an answer/guidance in solving this exercise. He kindly replied and here I post the answer he gave me:
Since a list comprehension returns a list not a number, x^n cannot be
defined as an instance of a list comprehension. Your solution x^n =
product [x | c <- [1..n]] is the correct one.
So, I guess I'll stick to the solution I posted (and discarded for using recursion):
foldr (*) 1 [x | c <- [1..n]]
He didn't say anything about creating a list of x^n elements with lists comprehensions (no recursion) though as #David Fletcher and #n.m point out in their comments, it might be impossible.
May be you can do as follows;
pow :: Int -> Int -> Int
pow 0 _ = 1
pow 1 x = x
pow n x = length [1 | y <- [1..x], z <- [1..pow (n-1) x]]
so pow 3 2 would return 8
I want to make a function that creates an infinite list that takes two numbers and an operator as input so it can generate arithmetic and geometric sequences.
infiniteList:: (Floating a)=>a->(a->a->a)->a->[a]
infiniteList start operation changeby =
start:[(operation x changeby)| x<-(infiniteList start operation changeby)]
the code compiles and works properly: infiniteList 1 (*) 2 generates a list starting from 1 and subsequent numbers are double its predecessor.
Now I'm having trouble figuring out the computational complexity "to calculate the nth element of the list". Technically it is doing one operation to figure out each element of the list. However, if you were after the (2^k +1) term, I would have to wait for the computer to finish calculating 2^(k+1) elements first.
I hope I'm explaining this properly, so basically I think the program produces the elments in 2^k batches where k is an integer, so you could potentially be waiting for ( 2^(k+1)-2^k) time to calculate the (2^k +1)th integer. So what is the computational complexity "to calculate the nth element of the list"?
A key tool is the following rule:
When analyzing the performance (not the totality) of a binding, you are allowed to assume, when analyzing its right-hand-side, that the binding itself has been fully evaluated.
You are defining infiniteList, so you are allowed to assume that in the RHS, the infiniteList binding has been fully evaluated. That, unfortunately, isn't useful, because infiniteList is just a function, and fully evaluating it just gives you the function!
But you can use this reasoning tool to figure out a fix: you have to bind the right thing.
infiniteList :: a -> (a -> a -> a) -> a -> [a]
infiniteList start operation changeby =
let result =
start : [operation x changeby | x <- result]
in result
Now you have a useful binding, result, which you can assume is fully evaluated! In the RHS, you now have, essentially,
start : map (\x -> operation x changeby) result
which is clearly O(n).
Indeed with the first definition,
> infiniteList 1 (*) 2 !! 10000
takes longer than I wish to wait, but with the modified definition, it takes a mere 0.04 seconds even in GHCi.
The run time depends a lot on how GHC decides to evaluate it.
To simplify things, consider this version of the function:
inf a f = a : [ f x | x <- inf a f ]
If GHC performed common sub-expression elimination on int a f, it could decide to evaluate it as if it had been written:
inf a f = let r = a : [ f x | x <- r ]
in r
and this runs in linear time.
I'm not sure where you are getting the "batches" idea from. Below is a transcript of the first few elements of the list. From that, I think you should be able to figure out the complexity.
What's the first element of the list? It is start, because infiniteList is defined as start:[something], and the first element of any list of that form is start.
What is the second element of the list? We certainly need to consult the [something] portion of the list above. The first element of that sublist is operation x changeby where x is the first element of infiniteList. We decided already that the first element is start, so the second element is operation start changeby, which is exactly what we wanted. What do we have to compute to get the second element? Just the first, plus the operation.
What is the third element of the list? It's the second element of [something], which is operation x changeby where x is the second element of infiniteList. Fortunately, we just calculated what that is...
What do we have to compute to get the third element? Just the first and second, plus the operation.
Although it doesn't directly answer the question, you should ask yourself what complexity you expect the function to have. How much work needs to be done to get the nth element? It's possible that your implementation in code is worse, but it might help you think about your code differently.
Just do some math, assume calculate nth item requires T(n) calculations, as
[(operation x changeby)| x<-(infiniteList start operation changeby)]
suggests, we need to know sub problem T(n-1), and the full list comprehension have n-1 operations, and then concat star:... operation is efficient, and have 1 calculation, so
T(n) = T(n-1) + (n - 1) + 1 = T(n-1) + n -> O(n^2)
Actually, you can "feel" the time complexity just by running some examples. Let f n = (infiniteList 0 (+) 1) !! n, then run f 10, f 100, f 1000, f 10000, you can see the difference.
Usually, when n=1000 runs in no time, n=10000 run some time like 1 or 2 seconds, and n=100000 run forever, it is usually O(n^2).
BTW, there is an O(n) approach:
infi :: a -> (a -> a -> a) -> a -> [a]
infi x f s = x : infi (f x s) f s
You can do some math and run some examples to feel the difference.
One strategy that sometimes helps with recursion is to expand it out a few times to get a better idea of what's going on. Let's try that:
infiniteList start operation changeby =
start:[(operation x changeby) | x <-
start:[(operation x changeby) | x <-
start:[(operation x changeby) | x <-
start:[(operation x changeby) | x <-
start:[(operation x changeby) | x <- (infiniteList start operation changeby)]]]]]
We can see the first element in the list is going to be start as expected. Then the second element will be start from the first recursive call passed through operation x changeby. What will the third item be? Well it'll be the second item of the first recursive call, so it'll be start passed through two calls of operation x changeby. Now the pattern emerges! In general, the nth item of infiniteList will be start with operation x changeby called on it n-1 times. This is rather unfortunate because ,as any student of computer science knows, 1 + 2 + ... + n - 1 = n(n-1)/2 = O(n^2).
There is, of course, a much more efficient way to write this function. Instead of applying operation x changeby to start n-1 times to get the nth item, why don't we just apply it once to the previous item? This will give us an O(n) solution. For example, we can use unfoldr from Data.List:
import Data.List (unfoldr)
infiniteList start operation changeby =
unfoldr (\x -> Just (x, operation x changeby)) start
I am repeatedly getting a stack overflow on my solution to Project Euler #7 and i have no idea why.
Here is my code:
import System.Environment
checkPrime :: Int -> Bool
checkPrime n = not $ testList n [2..n `div` 2]
--testList :: Int -> [Int] -> Bool
testList _ [] = False
testList n xs
| (n `rem` (head xs) == 0) = True
| otherwise = testList n (tail xs)
primesTill n = sum [1 | x <- [2..n], checkPrime x]
nthPrime n = nthPrime' n 2
nthPrime' n x
| (primesTill x == n) = x
| otherwise = nthPrime' n x+1
main = print (nthPrime 10001)
resolving the stackoverflow
As #bheklilr mentioned in his comment the stackoverflow is caused by a wrong evaluation order in the otherwise branch of the nthPrime' function:
nthPrime' n x+1
Will be interpreted as
(nthPrime' n x)+1
Because this expression is called recursively, your call of nthPrime' n 2 will expand into
(nthPrime' n 2)+1+1+1+1+1+1+1+1 ...
but the second parameter will never get incremented and your program collects a mass of unevaluated thunks. The evaluation can only happen if the first parameter is reduced to an Int, but your function is in an endless recursion so this will never take place. All the plus ones are stored on the stack, if there is no more space left you'll get a stackoverflow error.
To solve this problem you need to put parranteses around the x+1 so your recursive call will look like this
nthPrime' n (x+1)
Now the parameters gets incremented before it is passed to the recursive call.
This should solve your stackoverflow problem, you can try it out with a smaller number e.g. 101 and you'll get the desired result.
runtime optimization
If you test your program with the original value 10001 you may realize that it still won't finish in a reasonable amount of time.
I won't go into the details of fancy algorithms to solve this problems, if you're interested in them you can easily find them online.
Instead I'll show you were the problem in your code is and show you a simple solution.
The bottleneck is your nthPrime function:
primesTill n = sum [1 | x <- [2..n], checkPrime x]
nthPrime n = nthPrime' n 2
nthPrime' n x
| (primesTill x == n) = x
| otherwise = nthPrime' n (x+1)
This function checks if the number of primes between 2 and x is equal to n. The idea is correct, but it leads to an exponential runtime. The problem is that you recalculate primesTill x for every iteration. To count the primes smaller than x you calculate them all and than sum them up. In the next step for x+1 you forget every thing you know about the numbers between 2 and x and test them all again if they are prime only as a last step you test the if x+1 is prime. Than you repeat this - forget every thing and test all numbers again - until you are finished.
Wouldn't it be great if the computer could remember the primes it has already found?
There are many possibilities to do this I'll use a simple infinite list, if you are interested in other approaches you can search for the terms memoization or dynamic programming.
We start with the list comprehension you used in primesTill:
[1 | x <- [2..n], checkPrime x]
This calculates all primes between 2 and n, but immediately forgets the prime number and replaces it with 1, so the first step will be to keep the actual numbers.
[x | x <- [2..n], checkPrime x]
This gives us a list of all prime numbers between 2 and n. If we had a sufficiently large list of prime numbers we could use the index function !! to get the 10001st prime number. So we need to set n to a really really big number, to be sure that the filtered list is long enough?
Lazy evaluation to the rescue!
Lazy evaluation in haskell allows us to build an infinite list, that is only evaluated as much as needed. If we don't supply an upper bound to a list generator it will build such an infinite list for us.
[x | x <- [2..], checkPrime x]
Now we have a infinite list of all prime numbers.
We can bind it to the a name e.g. primes and use it to define nthPrime
primes = [x | x <- [2..], checkPrime x]
nthPrime n = primes !! n
Now you can compile it with ghc -O2, run it and the result will be promptly delivered to you.
I'm new to Haskell and tinkering around with the Euler Project problems. My solution for problem #3 is far too slow. At first I tried this:
-- Problem 3
-- The prime factors of 13195 are 5, 7, 13 and 29.
-- What is the largest prime factor of the number 600851475143 ?
problem3 = max [ x | x <- [1..n], (mod n x) == 0, n /= x]
where n = 600851475143
Then I changed it to return all x and not just the largest one.
problem3 = [ x | x <- [1..n], (mod n x) == 0, n /= x]
where n = 600851475143
After 30 minutes, the list is still being processed and the output looks like this
[1,71,839,1471,6857,59569,104441,486847,1234169,5753023,10086647,87625999,408464633,716151937
Why is it so slow? Am I doing something terribly wrong or is it normal for this sort of task?
With your solution, there are about 600 billion possible numbers. As noted by delnan, making every check of the number quicker is not going to make much difference, we must limit the number of candidates.
Your solution does not seem to be correct either. 59569 = 71 * 839 isn't it? The question
only asks for prime factors. Notice that 71 and 839 is in your list so you are
doing something right. In fact, you are trying to find all factors.
I think the most dramatic effect you get simply by dividing away the factor before continuing.
euler3 = go 2 600851475143
where
go cand num
| cand == num = [num]
| cand `isFactorOf` num = cand : go cand (num `div` cand)
| otherwise = go (cand + 1) num
isFactorOf a b = b `mod` a == 0
This may seem like an obvious optimization but it relies on the fact that if both a and b divides c and a is coprime to b then a divides c/b.
If you want to do more, the common "Only check until the square root" trick has been
mentioned here. The same trick can be applied to this problem, but the performance gain does not show, unfortunately, on this instance:
euler3 = go 2 600851475143
where
go cand num
| cand*cand > num = [num]
| cand `isFactorOf` num = cand : go cand (num `div` cand)
| otherwise = go (cand + 1) num
isFactorOf a b = b `mod` a == 0
Here, when a candidate is larger than the square root of the remaining number (num), we know that num must be a prime and therefore a prime factor of the original
number (600851475143).
It is possible to remove even more candidates by only considering prime numbers,
but this is slightly more advanced because you need to make a reasonably performant
way of generating primes. See this page for ways of doing that.
It's doing a lot of work! (It's also going to give you the wrong answer, but that's a separate issue!)
There are a few very quick ways you could speed it up by thinking about the problem a little first:
You are applying your function over all numbers 1..n, and checking each one of them to ensure it isn't n. Instead, you could just go over all numbers 1..n-1 and skip out n different checks (small though they are).
The answer is odd, so you can very quickly filter out any even numbers by going from 1..(n-1)/2 and checking for 2x instead of x.
If you think about it, all factors occur in pairs, so you can in fact just search from 1..sqrt(n) (or 1..sqrt(n)/2 if you ignore even numbers) and output pairs of numbers in each step.
Not related to the performance of this function, but it's worth noting that what you've implemented here will find all of the factors of a number, whereas what you want is only the largest prime factor. So either you have to test each of your divisors for primality (which is going to be slow, again) or you can implement the two in one step. You probably want to look at 'sieves', the most simple being the Sieve of Eratosthenes, and how you can implement them.
A complete factorization of a number can take a long time for big numbers. For Project Euler problems, a brute force solution (which this is) is usually not enough to find the answer in your lifetime.
Hint: you do not need to find all prime factors, just the biggest one.
TL;DR: The two things you were doing non-optimally, are: not stopping at the square root, and not dividing out each smallest factor, as they are found.
Here's a little derivation of the (2nd) factorization code shown in the answer by HaskellElephant. We start with your code:
f1 n = [ x | x <- [2..n], rem n x == 0]
n3 = 600851475143
Prelude> f1 n3
[71,839,1471,6857,59569,104441,486847Interrupted.
So it doesn't finish in any reasonable amount of time, and some of the numbers it produces are not prime... But instead of adding primality check to the list comprehension, let's notice that 71 is prime. The first number produced by f1 n is the smallest divisor of n, and thus it is prime. If it weren't, we'd find its smallest divisor first - a contradiction.
So, we can divide it out, and continue searching for the prime factors of newly reduced number:
f2 n = tail $ iterate (\(_,m)-> (\f->(f, quot m f)) . head $ f1 m) (1,n)
Prelude> f2 n3
[(71,8462696833),(839,10086647),(1471,6857),(6857,1),(*** Exception: Prelude.hea
d: empty list
(the error, because f1 1 == []). We're done! (6857 is the answer, here...). Let's wrap it up:
takeUntil p xs = foldr (\x r -> if p x then [x] else x:r) [] xs
pfactors1 n = map fst . takeUntil ((==1).snd) . f2 $ n -- prime factors of n
Trying out our newly minted solution,
Prelude> map pfactors1 [n3..]
[[71,839,1471,6857],[2,2,2,3,3,1259Interrupted.
suddenly we hit a new inefficiency wall, on numbers without small divisors. But if n = a*b and 1 < a <= b, then a*a <= a*b == n and so it is enough to test only until the square root of a number, to find its smallest divisor.
f12 n = [ x | x <- takeWhile ((<= n).(^2)) [2..n], rem n x == 0] ++ [n]
f22 n = tail $ iterate (\(_,m)-> (\f->(f, quot m f)) . head $ f12 m) (1,n)
pfactors2 n = map fst . takeUntil ((==1).snd) . f22 $ n
What couldn't finish in half an hour now finishes in under one second (on a typical performant box):
Prelude> f12 n3
[71,839,1471,6857,59569,104441,486847,600851475143]
All the divisors above sqrt n3 were not needed at all. We unconditionally add n itself as the last divisor in f12 so it is able to handle prime numbers:
Prelude> f12 (n3+6)
[600851475149]
Since n3 / sqrt n3 = sqrt n3 ~= 775146, your original attempt at f1 n3 should have taken about a week to finish. That's how important this optimization is, of stopping at the square root.
Prelude> f22 n3
[(71,8462696833),(839,10086647),(1471,6857),(6857,1),(1,1),(1,1),(1,1),(1,1),(1,
1),(1,1),(1,1),(1,1),(1,1),(1,1),(1,1),(1,1),(1,1),(1,1)Interrupted
We've apparently traded the "Prelude.head: empty list" error for a non-terminating - but productive - behavior.
Lastly, we break f22 up in two parts and fuse them each into the other functions, for a somewhat simplified code. Also, we won't start over anew, as f12 does, searching for the smallest divisor from 2 all the time, anymore:
-- smallest factor of n, starting from d. directly jump from sqrt n to n.
smf (d,n) = head $ [ (x, quot n x) | x <- takeWhile ((<=n).(^2)) [d..]
, rem n x == 0] ++ [(n,1)]
pfactors n = map fst . takeUntil ((==1).snd) . tail . iterate smf $ (2,n)
This expresses guarded (co)recursion through a higher-order function iterate, and is functionally equivalent to that code mentioned above. The following now runs smoothly, and we're even able to find a pair of twin primes as a bonus there:
Prelude Saga> map pfactors [n3..]
[[71,839,1471,6857],[2,2,2,3,3,1259,6628403],[5,120170295029],[2,13,37,227,27514
79],[3,7,7,11,163,2279657],[2,2,41,3663728507],[600851475149],[2,3,5,5,19,31,680
0809],[600851475151],[2,2,2,2,37553217197],[3,3,3,211,105468049],[2,7,11161,3845
351],[5,67,881,2035853],[2,2,3Interrupted.
Here is my solution for Euler Project #3. It takes only 1.22 sec on my Macbook Air.
First we should find all factors of the given number. But we know, that even numbers can't be prime numbers (except number 2). So, to solve Euler Project #3 we need not all, but only odd factors:
getOddFactors num = [ x | x <- [3,5..num], num `rem` x == 0 ]
But we can optimize this function. If we plan to find a factor of num greater than sqrt num, we should have another factor which is less than sqrt num - and these possible factors we have found already. Hence, we can limit our list of possible factors by sqrt num:
getOddFactors num = [ x | x <- [3, 5..(floor.sqrt.fromIntegral) num],
num `rem` x == 0 ]
Next we want to know which of our odd factors of num are prime numbers:
isPrime number = [ x | x <- [3..(floor.sqrt.fromIntegral) number],
number `rem` x == 0] == []
Next we can filter odd factors of num with the function isPrime to find all prime factors of num. But to use laziness of Haskell to optimize our solution, we apply function filter isPrime to the reversed list of odd factors of the num. As soon as our function finds the first value which is prime number, Haskell stops computations and returns solution:
largestPrimeFactor = head . filter isPrime . reverse . getOddDivisors
Hence, the solution is:
ghci> largestPrimeFactor 600851475143
6857
(1.22 secs, 110646064 bytes)
I am a really big noob to Haskell.
I have this code:
4 sieve n i = if i < n
5 then
6 do {
7 innerSieve n;
8 sieve n (i + 1);
9 }
10 else -1
11
12 innerSieve n = return n
13
14 --innerSieve n i j = [x | x <- [i..n], x `mod` j == 0]
and I have this error:
[1 of 1] Compiling Main ( sieve.hs, interpreted )
Ok, modules loaded: Main.
*Main> sieve 10 2
<interactive>:1:1:
No instance for (Num (m0 b0))
arising from a use of `sieve'
Possible fix: add an instance declaration for (Num (m0 b0))
In the expression: sieve 10 2
In an equation for `it': it = sieve 10 2
*Main>
I've been banging my head against a wall trying to understand what it means by "No instance for (Num (m0 b0))." What in the world is a m0 b0?
I thought this might help:
*Main> :t sieve
sieve :: (Ord a, Num a, Num (m b), Monad m) => a -> a -> m b
*Main>
EDIT:
I am trying to recreate the sieve of erastothenes by making a recursive function with a list comprehension, basically. I also want to -understand- everything in the code.
Your inner do block has a monadic type. This makes the entire result of sieve have a monadic type of (Monad m) => m b. The else branch of your if statement returns -1, so we know it also has a numeric type. This makes the result of your function (Num (m b), Monad m) => m b. This is very clearly wrong.
I can't figure out what your function is trying to accomplish, so I'm not sure where exactly you went wrong. I would recommend writing explicit type annotations on your functions, to express exactly what you're expecting each function to do. That will, at a minimum, give you better error messages, because instead of saying that the inferred type doesn't make sense, it can point you to exactly what expression doesn't match the explicit type.
BTW, you might find the if statement is better expressed as
sieve n i
| i < n = -- contents of the then block
| otherwise = -1
Haskell is a functional language. This especially means, that you don't tell the compiler Do A then do B but rather calculate A – You don't tell the compiler in what order to do things, rather you tell it what you want to know. You can think of that as having only one (return) statement. Thus, you need to rewrite your code to fit to this paradigma.
The do statement is for a special construct called monad that essentially allows stateful actions (such as printing to the screen) in a consistent manners. You don't need it.
As the others already showed you, you can do something like this. The pipe (|) is called pattern guard and essentially works like an If-then-else:
sieve n i | i < n = --result if condition is met
| otherwise = -1
Remember that you can't change the values of variables. You may need to rewrite your innerSieve to return something.
As others have said, you almost certainly dont want to use a do block in your code where you do. do is for Monads and should be avoided when learning Haskell, and is probably inappropriate since the only Monad here is [] which would ignore any definition of innerSieve. Haskell code describes values and types in terms of other values and types. Haskell programs dont tell the computer what to do, they tell it what is. This is a radical way of thinking, but a very powerful one. do notation is a special syntax for handling monads which are a special kind of value that can be used to encode computations (including imperative computations and state transitions) cleanly and efficiently, but it requires a broad understanding of Haskell to use well.
My advice to Haskell newbies is "Avoid monads and do notation until you have mastered: recursion, higher order functions, and typeclasses. You dont need do to test your programs (use GHCi), so learn the real functional way of thinking. Try to program such that your programs dont do anything!"
So, how would you go about writing a sieve of Eratosthenes in Haskell? There are many elegant ways. Warning: spoilers ahead. If you want to do this by yourself stop reading
You have commented out:
innerSieve n i j = [x | x <- [i..n], x `mod` j == 0]
I'm not sure what the point of n and i are here. It would be more elegant to write
innerSieve j ls = [x | x <- ls, x `mod` j == 0]
which has the type
innerSieve :: Integral x => x -> [x] -> [x]
so, in other words, it takes a list a value of some type x such that that type can be treated like an integer, and returns all the integral multiples of the original value.
You could use this to write the sieve of Eratosthenes, but a better way would be to get all the values that are not multiples. The reason is that, then you can just stack a bunch of these together to produce your full prime sieve
innerSieve j ls = [x | x <- ls, x `mod` j /= 0]
Here the /= is Haskell's way of saying "not equal". Cool, so lets build a prime sieve out of this
sieve (x:xs) = x : sieve (innerSieve x xs)
sieve [] = []
What does this say? well it takes a list of numbers, and gives you back a new list consisting of the first of those numbers, and the sieve applied to the rest of those numbers except for those that are multiples of the first one. The (x:xs) is a pattern that matches any list other than the empty list, binding x with the head of the list, and xs with the tail of the list. [] is a pattern that matches any empty list.
Finally, you can define the infinite list of all primes
primes = sieve [2..]
The expression [2..] generates the list 2,3,4,5,6,7,etc going on forever. Looks scary (infinite lists), but is okay because of Haskell's famed lazy evaluation. To get the nth prime you can say:
nthPrime n = primes !! (n - 1)
which just indexes into the list of primes. Haskell will only compute the minimum needed to return the result, so this function will terminate even though primes is infinitely long
or to get all the primes up to a number
primesUpToN n = take n primes
so, your entire code base ends up being:
sieve [] = []
sieve (x:xs) = x : sieve (innerSieve x xs) where
innerSieve j ls = [x | x <- ls, x `mod` j /= 0]
primes = sieve [2..]
nthPrime n = primes !! (n - 1)
primesUpToN n = take n primes
This isn't really the sieve of Eratosthenes, since you aren't "marking off" values. But, this sieve is actually "better" insofar as it is both faster and defines the set of all primes, rather than those up to a number. It is not how you should ever actually go about generating primes, but in 6 lines of code (most of which are unnecessary), it is hard to argue that mutation or looping makes things simpler.
Not only does this give a type error:
do {
innerSieve n;
sieve n (i + 1);
}
But it has the exact same value as
do {
sieve n (i + 1);
}
You have called a function "innerSeive", but then not done anything with the value.
If you would like to compute a value and then use the value in the next operation, use the (>>=) operator (sugared as let x = innerseive n; f2 n; within a do block).
However, for these mathematical functions, stay far, far away from do, let, (>>=), etc.