So I'm totally new to Haskell, hope it doesn't show too much. By any means, I was trying to create a function to determine if a number is prime. The basic idea is this: Given a number, see if it is divisible by any other number less than it. If so, return false. If not, it's prime, return true. The code so far (that is known to be working) is this:
divisible :: Integer -> Integer -> Bool
divisible x 2 = even x
divisible x y = ((x `mod` y) /= 0) && not (divisible x (y-1))
isPrime :: Integer -> Bool
isPrime x = not (even x) && not (divisible x (x-1))
Produces:
ghci> isPrime 9
False
ghci> isPrime 13
True
What I'd like to do is optimize this a bit, since I only need to check values less than or equal to sqrt(x). The problem is, when I try and implement this, stuff gets crazy:
isPrime x = not (even x) && not (divisible x (ceiling(sqrt(fromIntegral(x-1)))))
Besides the fact that it looks terrible (I said I was new), it doesn't give the correct result:
ghci> isPrime 9
False
ghci> isPrime 13
False
I'm trying to figure out what changed, because:
ghci> ceiling(sqrt(13))
4
Seems to be giving me the correct number. I know this is a small problem, but I'm seriously confused...
You got your conditions mixed up:
divisible x y = ((x `mod` y) /= 0) && not (divisible x (y-1))
should be
divisible x y = (x `mod` y) == 0 || divisible x (y-1)
for the test to work.
As is, your divisible function expands e.g.
divisible 21 5 = (21 `mod` 5 /= 0) && not (divisible 21 4)
= (21 `mod` 5 /= 0) && not ((21 `mod` 4 /= 0) && not (divisible 21 3))
= not ((21 `mod` 4 /= 0) && not ((21 `mod` 3 /= 0) && not (divisible 21 2)))
= not (True && not (False && not (divisible 21 3)))
= not (not False)
= False
since 21 `mod` 3 == 0, and isPrime 21 evaluates to True with the square root bound.
However, I get
*StrangePrime> isPrime 9
True
*StrangePrime> isPrime 13
True
with your code using the square root.
Without the square root, it happened to work for odd numbers, because the difference between an odd composite and any of its divisors is always even. Unfolding divisible a few steps for n = p*m, where p is the smallest prime factor of the odd composite n, we see
divisible n (n-1) = n `mod` (n-1) /= 0 && not (divisible n (n-2))
= not (divisible n (n-2))
= not (n `mod` (n-2) /= 0 && not (divisible n (n-3)))
= not (not (divisible n (n-3)))
= not^2 (divisible n (n-3))
and inductively
divisible n (n-1) = not^(k-1) (divisible n (n-k))
if there are no divisors of n larger than n-k. Now, in the above situation, the largest divisor of n is m = n - (p-1)*m, so we obtain
divisible n (n-1) = not^((p-1)*m-1) (divisible n m)
= not^((p-1)*m-1) (n `mod` m /= 0 && not (...))
But n `mod` m == 0, so we have
divisible n (n-1) = not^((p-1)*m-1) False
Since p is odd, p-1 is even, and hence so is (p-1)*m, so altogether we have an odd number of nots, which is the same as one not, giving
divisible n (n-1) = True
isPrime n = not (even n) && not (divisible n (n-1)) = True && not True = False
If p is an odd prime, the unfolding reaches divisible p (p-1) = not^(p-3) (divisible p (p - (p-2))). p-3 is even, divisible p 2 is even p, which is False.
Generally, consider divisible n s for an odd n, and let d be the largest divisor of n not exceeding s, if n is composite, or d = 2 if n is prime. The unfolding of divisible n s still proceeds the same way
divisible n s = not^k (divisible n (s-k))
while no divisor has been found and s-k > 2. So in the case of a composite n, we find
divisible n s = not^(s-d) (divisible n d)
= not^(s-d) (n `mod` d /= 0 && not (...))
= not^(s-d) False
= odd (s-d)
= even s -- since d is odd, as a divisor of an odd number
and in the case of an odd prime n,
divisible n s = not^(s-2) (divisible n 2)
= not^(s-2) (even n)
= not^(s-2) False
= odd s
So divisible n s measures the parity of the distance of s to the next smaller divisor of n or to 2, whichever is larger. When s was n-1, the starting point was always even, so it worked out correctly, but ceiling (sqrt (fromIntegral (n-1))) can be odd, in which case the results are flipped and composites are declared prime and vice versa.
You can make your divisible function work for the primality test of odd numbers with a square root bound if you make sure that the first call gets an even second argument (so if ceiling (sqrt (fromIntegral (n-1))) is odd, start at ceiling (sqrt (fromIntegral (n-1))) + 1), but the logic of that function is confusing, and its name doesn't correctly describe its results.
A more idiomatic way to write it would be
isPrime n = and [n `mod` k /= 0 | k <- [2 .. ceiling (sqrt $ fromIntegral n)]]
The test becomes more efficient when one skips candidate divisors that are already known to be nondivisors from prior tests, easy is skipping all even numbers except 2,
isPrime 2 = True
isPrime n = all ((/= 0) . (n `mod`)) (2 : [3, 5 .. ceiling (sqrt (fromIntegral n))])
slightly more involved, but still more efficient is also skipping multiples of 3
isPrime n = all ((/= 0) . (n `mod`)) (takeWhile (<= bound) (2:3:scanl (+) 5 (cycle [2,4])))
where
bound = ceiling (sqrt (fromIntegral (n-1)))
In the same vein one can eliminate the multiples of more small primes from the trial divisors, each gaining a bit of efficiency, but at the cost of a more complicated wheel, e.g. also eliminating multiples of 5 leads to
isPrime n = all ((/= 0) . (n `mod`)) (takeWhile (<= bound) (2:3:5: scanl (+) 7 (cycle [4,2,4,2,4,6,2,6])))
where
bound = ceiling (sqrt (fromIntegral (n-1)))
Here's how I'd do it:
divisibleBy :: (Integral a) => a -> a -> Bool
divisibleBy x y = mod x y == 0
isPrime :: (Integral a) => a -> Bool
isPrime x = or $ map (divisibleBy x) [2..(x-1)]
divisibleBy is a simple test of divisibility. isPrime performs this test on all integers between 1 and x, returning true if x is divisible by any of those integers. You might change the upper bound to root x, as you've done in your code, but otherwise this works.
Related
I found this solution on the internet and I need some help understanding it:
isPrime' :: Integer -> Bool
isPrime' n = foldr (\x acc -> (n `rem` x) /= 0 && acc) True primes
where primes = 2 : filter isPrime' [3,5..]
A couple of things:
My understanding is that if the accumulator for a fold function is a Boolean it has to be set in the lambda function itself. Something like:
(\x acc -> if (n `rem` x /= 0) then False else acc) True primes
But here it is not the case.
Also, the range being used for primes does not have a terminating number. I know the reason this works is because of Haskell's lazy evaluation, but how exactly is that working here?
Lastly, this function does not seem like it would return the proper Boolean. A prime number is one that has no other divisors but itself and 1. So shouldnt the lambda read:
(\x acc -> if (n `rem` x) == 0 then False else acc) True primes
I am thoroughly confused. Please help me out.
At least for me, your code doesn't finish. It is missing the stop condition, which can be seen in a similar solution from the wiki:
isPrime n = n > 1 &&
foldr (\p r -> p*p > n || ((n `rem` p) /= 0 && r)) True primes
primes = 2 : filter isPrime [3,5..]
Here you can see, that the condition p*p > n produces True, when there is no possible prime factor left. Because of lazy execution the right part of || is not evaluated and the foldr stops.
having
primes = [p1, p2, p3, ..., pn, ...]
calculating
isPrime' n = foldr (\x acc -> (n `rem` x) /= 0 && acc) True primes
is as if calculating
isPrime' n = rem n p1 /= 0 && (
rem n p2 /= 0 && (
rem n p3 /= 0 && (
..........
rem n pk /= 0 && (
.......... ..... ))))
For composite ns this works – one of the rem expressions will be 0, the inequality is false, and the whole expression is false too, because && is short-circuiting, lazy in its 2nd argument.
For prime ns this will cause a problem: none of the rem expressions will be 0, by definition of a prime, until we reach a prime p_i == n itself among the primes. But it's not there yet, as we haven't detected it as being prime yet - we're just doing it right now. To test whether it is prime, we must know that it is prime - clearly a bad situation.
A value will be demanded from primes which is not there yet. This is known as "black hole". It causes an error, and calculation aborts (or becomes stuck).
To put it differently, it is as if the definition
primes = 2 : filter isPrime' [3,5..]
were defined as
primes = 2 : [ n | n <- [3,5..]
, and [rem n p /= 0 | p <- takeWhile (< n) primes]]
The problem is that to stop when n is prime, takeWhile (< n) must reach a prime p above or equal to n in primes, but it's not there yet. "Black hole".
The famous "sieve" code gets around this problem by "transposing" the workflow,
primes = map head . iterate (\(x:xs)-> filter ((/=0).(`rem`x)) xs) $ [2..]
thus making it work while retaining its computational inefficiency (the lesser problem of your code), testing its candidates by too many primes needlessly (where each prime is tested by all its preceding primes instead of just those not above its square root), making it unnecessarily slow.
This is mitigated by putting a properly early stop to the testing, with
primes = 2 : [ n | n <- [3,5..]
, and [rem n p /= 0 | p <- takeWhile ((<= n).(^2)) primes]]
which, back in terms of your definition, is equivalent to
isPrime' n = p1*p1 > n || rem n p1 /= 0 && (
p2*p2 > n || rem n p2 /= 0 && (
p3*p3 > n || rem n p3 /= 0 && (
..........
pk*pk > n || rem n pk /= 0 && (
.......... ..... ))))
You can write this down as a foldr-based definition now (which can be seen in another answer here).
The expression
(n `rem` x) /= 0
clearly produces a Bool result. The parameter acc is already a Bool value. So
(n `rem` x) /= 0 && acc
is a logical-AND of two Bool values, which clearly produces a Bool result. Where is the confusion?
The input list is infinite, consisting only of odd numbers. So long as you can produce a result after examining only a finite number of values, laziness makes everything fine.
I am creating a function to factorize any given number in haskell. And so i have created this:
primes :: [Integer]
primes = 2:(sieve [3,5..])
where
sieve (p:xs) = p : sieve [x |x <- xs, x `mod` ((p+1) `div` 2 ) > 0]
factorize 2 = [2]
factorize x
| divisible x = w:(factorize (x `div` w))
| otherwise = [x]
where
divisible :: Integer -> Bool
divisible y = [x |x <- (2:[3,5..y]), y `mod` x == 0] /= []
firstfactor :: Integer -> [Integer] -> Integer
firstfactor a (x:xs)
| a `ifdiv` x = x
| otherwise = firstfactor a xs
firstfactor a _ = a
ifdiv x y = mod x y == 0
w = firstfactor x primes
The function works fine, but appends 1 to the end of the list, for example factorize 80 would give this list: [2,2,2,2,5,1] My question is, why does this happen?
This comes up from two parts of the code. Firstly, factorize 1 is [1]. Secondly, since x is always divisible by itself, your very final call will always have w == x, so the recursion will be w:(factorize (w `div` w)) which is always w:(factorize 1).
To solve this, you can just add an extra base case to throw out the factors of 1:
factorize 1 = []
factorize ...
Also, you can drop the factorize 2 = [2] case because it gets subsumed by the otherwise case you already have.
factorize 1 = [] makes sense mathematically, because 1 has no prime factors (remember that 1 is not a prime number itself!). This follows the same logic behind product [] = 1—1 is the identity for multiplication, which makes it the "default" value when you have nothing to multiply.
Here is the code I am trying to use: This should generate all primes up to 100
sieve_primes = [x | x<-[2..100], y<-[2..50], z <-[2..25], (x*z) `mod` y /= 0]
The code
isPrime n = length [x | x<-[2..n], n `mod` x == 0] == 1
computes all the factors just to count them. You don't need to count them: as soon as the second factor is found you can stop your search without checking for further ones.
So, either replace length ... == 1 with a custom predicate, or take 2 elements from the list comprehension before checking its length.
What you had in mind was probably
Prelude> [x| x<-[2..100], not $ elem x [y*z| y<-[2..50], z<-[2..25]]]
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
This is very slow. At least we can rearrange the pieces,
Prelude> [x| let sieve=[y*z| y<-[2..50], z<-[2..25]],
x<-[2..100], not $ elem x sieve]
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
This is still very slow, for any number much above even 1000 (where you'd use 500 and 250). Then again, why the 25 (250) limit? Your code follows the
primes = [x| x<-[2..], not $ elem x
[y*z| y<-[2..x`div`2], z<-[2..min y (x`div`y)]]]
idea, i.e. y*z = 2*y .. min (y*y) x, so with the known top limit (x <= n) it should be
primesTo n = [x| let sieve=[y*z| y<-[2..n`div`2], z<-[2..min y (n`div`y)]],
x<-[2..n], not $ elem x sieve]
(incidentally, max (min y (n/y)) {y=2..n/2} = sqrt n, so we could've used 10 instead of 25, (and 31 instead of 250, for the 1000)).
Now 1000 is not a problem, only above ~ 10,000 we again begin to see that it's slow (still), running at n2.05..2.10 empirical orders of growth (quick testing interpreted code in GHCi at n = 5000, 10000, 15000).
As for your second (now deleted) function, it can be rewritten, step by step improving its speed, as
isPrime n = length [x | x<-[2..n], n `mod` x == 0] == 1
= take 1 [x | x<-[2..n], n `mod` x == 0] == [n]
= [x | x<- takeWhile ((<=n).(^2)) [2..n], n `mod` x == 0] == []
= and [n `mod` x > 0 | x<- takeWhile ((<=n).(^2)) (2:[3,5..n])]
now, compiled, it can get first 10,000 primes in few tenths of a second.
I'm very new to Haskell (and functional programming in general), and I'm trying some basic exercises to try to get an understanding of the language. I'm writing a "naive" prime number checker that divides each number under the input to check if there is any remainder. The only constructs I've learned so far are comprehension lists and recursive functions, so I'm constrained to that. Here's what I'm trying:
isprime 1 = False
isprime 2 = True
isprime n = isprimerec n (n-1)
isprimerec _ 1 = False
isprimerec n t = if (n `rem` t) == 0 then False else isprimerec n (n-1)
The intention is that the user would use isprime n. Then isprime would use isprimerec to determine if the number is prime. It's a pretty round-about way of doing it, but I don't know any other way with my limited knowledge of Haskell.
Here's what happens when I try this:
isprimerec 10 9
Runs forever. I have to use Ctrl+C to stop it.
isprimerec 10 5
Returns False. The else part is never evaluated, so the function never calls itself.
I'm not sure why this is happening. Also, is this anywhere near close to how a Haskell programmer would approach this problem? (And I don't mean checking primality, I know this isn't the way to do it. I'm just doing it this way as an exercise).
The problem is in this line
isprimerec n t = if (n `rem` t) == 0 then False else isprimerec n (n-1)
You use (n - 1) as the second argument where it should be (t - 1). A further point, I think you want the isprimerec _ 1 case = True.
As to your more general question of whether or not this is idiomatic, I think you're on the right track. ghci has a decent command line debugger. I found this by putting your code in a file, loading it, and then issuing the command :break isprimerec. I then called your function and stepped through it with :step.
Your bug is a simple typo; at the end of isprimerec, your second parameter becomes n-1 instead of t-1. But that aside, the function isn't quite idiomatic. Here's the first pass of how I would write it:
isPrime :: (Ord a, Integral a) => a -> Bool
isPrime n | abs n <= 1 = False
isPrime 2 = True
isPrime n = go $ abs n - 1
where go 1 = False
go t = (n `rem` t /= 0) && go (t-1)
(I might call go something like checkDivisors, but go is idiomatic for a loop.) Note that this exposes the bug in your code: once go is local to isPrime, you don't need to pass n around, and so it becomes clearer that recursing on it is incorrect. The changes I made were, in rough order of importance:
I made isprimerec a local function. Nobody else would need to call it, and we lose the extra parameter.
I made the function total. There's no reason to fail on 0, and not really any reason to fail for negative numbers. (Technically speaking, p is prime if and only if -p is prime.)
I added a type signature. It's a good habit to get into. Using Integer -> Bool, or even Int -> Bool, would also have been reasonable.
I switched to interCaps instead of alllowercase. Just formatting, but it's customary.
Except I'd probably make things terser. Manual recursion is usually unnecessary in Haskell, and if we get rid of that entirely, your bug becomes impossible. Your function checks that all the numbers from 2 to n-1 don't divide n, so we can express that directly:
isPrime :: (Ord a, Integral a) => a -> Bool
isPrime n | abs n <= 1 = False
| otherwise = all ((/= 0) . (n `rem`)) [2 .. abs n - 1]
You could write this on one line as
isPrime :: (Ord a, Integral a) => a -> Bool
isPrime n = abs n > 1 && all ((/= 0) . (n `rem`)) [2 .. abs n - 1]
but I wouldn't be surprised to see either of these last two implementations. And as I said, the nice thing about these implementations is that your typo isn't possible to make in these representations: the t is hidden inside the definition of all, and so you can't accidentally give it the wrong value.
Your else branch is broken since it calls isprimerec n (n-1) every time. You probably ought to write isprimerec n (t-1) instead to have it count down.
You could also use a higher-order function all to make this a lot simpler.
isprime 1 = False
isprime n = all (\t -> n `rem` t /= 0) [2..(n-1)]
So OK, you've got the two bugs: your
isprimerec _ 1 = False
isprimerec n t = if (n `rem` t) == 0 then False else isprimerec n (n-1)
should have been
isprimerec _ 1 = True
isprimerec n t = if (n `rem` t) == 0 then False else isprimerec n (t-1)
or, with list comprehension,
isprime n = n>1 && and [ rem n t /= 0 | t <- [n-1,n-2..2] ]
(Internalize that extra parameter t, it was a technicality anyway! -- A-ha, but what's that and, you ask? It's just like this recursive function, foldr (&&) True :: [Bool] -> Bool.)
But now a major algorithmic drawback becomes visually apparent: we test in the wrong order. It will be faster if we test in ascending order:
isprime n = n>1 && and [ rem n t /= 0 | t <- [2..n-1] ]
or even much faster yet if we stop at the sqrt,
isprime n = n>1 && and [ rem n t /= 0 | t <- [2..q] ]
where q = floor (sqrt (fromIntegral n))
or test only by odds, after the 2 (why test by 6, if we've tested by 2 already?):
isprime n = n>1 && and [ rem n t /= 0 | t <- 2:[3,5..q] ]
where q = floor (sqrt (fromIntegral n))
or just by primes (why test by 9, if we've tested by 3 already?):
isprime n = n>1 && and [ rem n t /= 0 | t <- takeWhile ((<= n).(^2)) primes ]
primes = 2 : filter isprime [3..]
And why test the evens when filtering the primes through - isn't it better to not generate them in the first place?
primes = 2 : filter isprime [3,5..]
But isprime always tests division by 2 -- yet we feed it only the odd numbers; so,
primes = 2 : 3 : filter (noDivs (drop 1 primes)) [5,7..]
noDivs factors n = and [ rem n t /= 0 | t <- takeWhile ((<= n).(^2)) factors ]
And why generate the multiples of 3 (i.e. [9,15 ..] == map (3*) [3,5..]), only to test and remove them later? --
{- [5,7..]
== [j+i | i<-[0,2..], j<-[5]] -- loop unrolling, 3x:
== [j+i | i<-[0,6..], j<-[5,7,9]]
== 5:[j+i | i<-[0,6..], j<-[7,9,11]]
== 5:[7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43, ...
\\ [ 9, 15, 21, 27, 33, 39, ...
== [j+i | i<-[0,6..], j<-[ 9 ]]
-}
primes = 2:3:5: filter (noDivs (drop 2 primes))
[j+i | i<-[0,6..], j<-[7, 11]]
We can skip over the multiples of 5 in advance as well (as another step in the Euler's sieve, euler (x:xs) = x : euler (xs `minus` map (x*) (x:xs))):
-- [j+i | i<-[0, 6..], j<-[7, 11]] -- loop unrolling, 5x:
-- == 7:[j+i | i<-[0,30..], j<-[11,13,17,19,23,25,29,31,35,37]]
-- \\ [j+i | i<-[0,30..], j<-[ 25, 35 ]]
primes = 2:3:5:7: filter (noDivs (drop 3 primes))
[j+i | i<-[0,30..], j<-[11,13,17,19,23, 29,31, 37]]
... but that's already going far enough, for now.
I'm new to Haskell, and I'm trying a bit:
isPrime :: Integer->Bool
isPrime x = ([] == [y | y<-[2..floor (sqrt x)], mod x y == 0])
I have a few questions.
Why when I try to load the .hs, WinHugs say: Instances of (Floating Integer, RealFrac Integer) required for definition of isPrime?
When the interpreter finds one element in the right set, it immediately stops or it computes all the set? I think you know what I mean.
Sorry about my english.
1) The problem is that sqrt has the type (Floating a) => a -> a, but you try to use an Integer as argument. So you have to convert your Integer first to a Floating, e.g. by writing sqrt (fromIntegral x)
2) I see no reason why == shouldn't be lazy, but for testing for an empty collection you can use the null function (which is definitely lazy, as it works on infinite lists):
isPrime :: Integer->Bool
isPrime x = null [y | y<-[2..floor (sqrt (fromIntegral x))], x `mod` y == 0]
But in order to get an more idiomatic solution, break the problem into smaller sub-problems. First, we need a list of all elements y with y*y <= x:
takeWhile (\y -> y*y <= x) [2..]
Then we need only the elements that divide x:
filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..])
Then we need to check if that list is empty:
isPrime x = null (filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..]))
And if this looks to lispy to you, replace some of the parens with $
isPrime x = null $ filter (\y -> x `mod` y == 0) $ takeWhile (\y -> y*y <= x) [2..]
For additional clarity you can "outsource" the lambdas:
isPrime x = null $ filter divisible $ takeWhile notTooBig [2..] where
divisible y = x `mod`y == 0
notTooBig y = y*y <= x
You can make it almost "human readable" by replacing null $ filter with not $ any:
isPrime x = not $ any divisible $ takeWhile notTooBig [2..] where
divisible y = x `mod`y == 0
notTooBig y = y*y <= x
Because sqrt has the type Floating a => a -> a. This means the input has to be a Floating type and the output will be the same type. In other words x needs to be a Floating type. However you declared x to be of type Integer, which is not a Floating type. In addition floor needs a RealFrac type, so x needs to be that as well.
The error message suggests that you fix that by making Integer a Floating type (by defining an instance Floating Integer (and the same for RealFrac).
Of course this is not the correct approach in this case. Rather you should use fromIntegral to convert x to a Real (which is an instance of Floating and RealFrac) and then give that to sqrt.
Yes. As soon as == sees that the right operand has at least one element, it knows it is not equal to [] and thus returns False.
That being said, null is a more idiomatic way to check whether a list is empty than [] ==.
Regarding the second point, it stops, for example:
[] == [x | x <- [1..]]
Returns False
Landei's solution is great, however, if you want a more efficient¹ implementation we have (thanks to BMeph):
-- list of all primes
primes :: [Integer]
primes = sieve (2 : 3 : possible [1..]) where
sieve (p : xs) = p : sieve [x | x <- xs, x `mod` p > 0]
possible (x:xs) = 6*x-1 : 6*x+1 : possible xs
isPrime :: Integer -> Bool
isPrime n = shortCircuit || (not $ any divisible $ takeWhile inRangeOf primes) where
shortCircuit = elem n [2,3] || (n < 25 && ((n-1) `mod` 6 == 0 || (n+1) `mod` 6 == 0))
divisible y = n `mod` y == 0
inRangeOf y = y * y <= n
The 'efficiency' comes from the use of constant primes. It improves the search in two ways:
The Haskell runtime could cache the results so subsequent invocations are not evaluated
It eliminates a range of numbers by logic
note that the sieve value is simply a recursive table, where says the head of
the list is prime, and adds it to it. For the rest of the lists if there is no
other value already in the list that composes the number then its also prime
possible is list of all possible primes, since all possible primes are in the
form 6*k-1 or 6*k-1 except 2 and 3
The same rule is applied for shortCircuit too to quickly bail out of calculations
Footnote by D.F.
¹ It's still a terribly inefficient way to find primes. Don't use trial division if you need primes larger than a few thousand, use a sieve instead. There are several far more efficient implementations on hackage.
I think WinHugs needs to import a module for Integer and etc... Try Int
The interpreter will not compute anything until you call e.g. isPrime 32 then it will lazily compute the expression.
PS your isPrime implementation is not the best implementation!