My goal is to write a function that calculates the maximum Collatz number below a certain number 'n'. (It's a Project Euler question for those who are familiar.)
Some context: A Collatz number for a given integer is equal to the length of the Collatz sequence for that integer. A Collatz sequence for an integer is calculated as follows: the first number ("n0") in the sequence is that integer itself; if n0 is even, the next number in the sequence ("n1") is equal to n / 2; if n0 is odd, then n1 is equal to 3 * n0 + 1. We continue recursively extending the sequence until we arrive at 1, at which point the sequence is finished. For example, the collatz sequence for 5 is: {5, 16, 8, 4, 2, 1} (because 16 = 3 * 5 + 1, 8 = 16 / 2, 4 = 8 / 2,...)
I'm trying to write a function ("maxCollatzUnder") which, when passed an integer "m", returns the integer (less than or equal to m) which has the longest Collatz sequence (i.e., largest Collatz number). For example, maxCollatz 20 (i.e., what integer below (inclusive) 20 has the longest collage sequence?) should return 19 (the number 19 has a Collatz sequence of length 21: [19,58,29,88,44,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]).
In the code below, the "collatz" and "collatzHelper" functions compile and run correctly. I'm having trouble with the "maxCollatzUnder" function. This function intends to (I) create a list of 2-tuples (x,y) for each integer x ranging from 1 to m (where m is the function argument) and where where y represents the Collatz number for integer x and then (II) look through the list for the highest Collatz number (i.e., y) and return its associated integer (i.e., x)
maxCollatzUnder n = foldl(\acc (i,j) -> if j > acc then i else acc) 0
(zip [1..n] ( map collatzLength [1..n]))
where collatzLength n = length . collatz $ n
collatz n = map truncate $ collatzHelper n
collatzHelper 0 = [0]
collatzHelper 1 = [1]
collatzHelper n
| (truncate n) `mod` 2 == 0 = [n] ++ collatzHelper (n/2)
| otherwise = [n] ++ collatzHelper (3*n+1)
I get the following error when I (attempt to) compile.
*Main> :l PE14Collatz.hs
[1 of 1] Compiling Main ( PE14Collatz.hs, interpreted )
PE14Collatz.hs:7:89:
No instance for (RealFrac Int)
arising from a use of `collatzLength'
In the first argument of `map', namely `collatzLength'
In the second argument of `zip', namely
`(map collatzLength [1 .. n])'
In the third argument of `foldl', namely
`(zip [1 .. n] (map collatzLength [1 .. n]))'
Failed, modules loaded: none.
What's curious is that the code compiles and runs correctly if I change the "maxCollatzUnder" to the following code (see below). The only change is that, in the version below, the fold function returns "j" (i.e., the largest Collatz number) instead of "i" (i.e., the integer which generates the largest Collatz number).
maxCollatzUnder n = foldl(\acc (i,j) -> if j > acc then j else acc) 0
(zip [1..n] ( map collatzLength [1..n]))
where collatzLength n = length . collatz $ n
Suggestions on a more efficient/elegant approach are welcome though I would still be interested in understanding the cause of this error.
Because of your use of truncate (a method of RealFrac) and / (a method of Fractional, a superclass of RealFrac), Haskell infers the following two type signatures for your last two functions:
collatz :: (RealFrac a, Integral b) => a -> [b]
collatzHelper :: RealFrac a => a -> [a]
Haskell then tries to deduce the type of maxCollatzUnder, and its thought process goes like this:
"In collatzLength n = length . collatz $ n, we're passing n to collatz, so the argument to collatzLength must be a RealFrac."
"Therefore, in map collatzLength [1..n], [1..n] must be a list of RealFrac values."
"Therefore, the n in map collatzLength [1..n] must be a RealFrac type."
"Therefore, the n in zip [1..n] (which is the same n) must be a RealFrac type, and so [1..n] is a list of RealFracs."
"Therefore, the i in (\acc (i,j) -> if j > acc then i else acc) must be a RealFrac."
"Because the aforementioned lambda can return either i or acc, they must be the same type."
"Because j is being compared to acc, j must be the same type as acc — and thus the same type as i and a RealFrac."
"But wait— j is the return value from collatzLength, which is the return value of a call to length, and so it has to be an Int, but Int isn't in RealFrac!"
"ERROR! ERROR!"
I have to go now (the Compiler Cabal doesn't like me giving away their secrets), but the shortest fix is to not use truncate and / and just use div for (floored) integer division.
Related
I recently started learning Haskell. To train a bit I wanted to try generating the list of prime numbers via self reference using the following code:
main = do
print (smaller_than_sqrt 4 2)
print (smaller_than_sqrt_list 5 [2..])
print ("5")
print (is_prime 5 [2..])
print ("7")
print (is_prime 7 [2..])
print ("9")
print (is_prime 9 [2..])
print ("test")
print (take 5 primes) -- Hangs
-- Integer square root
isqrt :: Int -> Int
isqrt = ceiling . sqrt . fromIntegral
-- Checks if x is smaller than sqrt(p)
smaller_than_sqrt :: Int -> Int -> Bool
smaller_than_sqrt p x = x <= isqrt p
-- Checks if x doesn't divide p
not_divides :: Int -> Int -> Bool
not_divides p x = p `mod` x /= 0
-- Takes in a number and an ordered list of numbers and only keeps the one smaller than sqrt(p)
smaller_than_sqrt_list :: Int -> [Int] -> [Int]
smaller_than_sqrt_list p xs = takeWhile (smaller_than_sqrt p) xs
-- Checks if p is prime by looking at the provided list of numbers and checking that none divides p
is_prime :: Int -> [Int] -> Bool
is_prime p xs = all (not_divides p) (smaller_than_sqrt_list p xs)
-- Works fine: primes = 2 : [ p | p <- [3..], is_prime p [2..]]
-- Doesn't work:
primes = 2 : 3 : [ p | p <- [5..], is_prime p primes]
But for some reason referencing primes inside of primes hangs when running runhaskell and is detected as a loop error when running the compiled binary with ghc.
However I don't really understand why.
Clearly, the first two elements of primes are 2 and 3. What comes after that? The next element of primes is the first element of
[p | p <- [5..], is_prime p primes]
What's that? It could be 5, if is_prime 5 primes, or it could be some larger number. To find out which, we need to evaluate
smaller_than_sqrt_list 5 primes
Which requires
takeWhile (<= isqrt 5) primes
Which requires
takeWhile (<= 3) primes
Well, that's easy enough, it starts with 2:3:..., right? Okay, but what's the next element? We need to look at the third element of primes and see whether it's less or equal to 3. But the third element of primes is what we were trying to calculate to begin with!
The problem is that smaller_than_sqrt 5 3 is still True. To compute whether 5 is a prime, the is_prime 5 primes expands to all (not_divides 5) (takeWhile (smaller_than_sqrt 5) primes), and takeWhile will attempt to iterate primes until the predicate no longer holds. It does hold for the first element (2), it still does hold for the second element (3), will it hold for the next element - wait what's the next element? We're still computing which one that is!
It should be sufficient to use floor instead of ceiling in isqrt, or simpler just
smaller_than_sqrt p x = x * x <= p
My factorial function seems to work for numbers between 1 and 6, but not for numbers much bigger than 6, for example starting with 21! the results are negative.
I cannot figure out why. Here's my function:
factorial :: Int -> Int
factorial 0 = 1
factorial 1 = 1
factorial num = num * factorial( num - 1)
And here's my binomial coefficient function that calls my factorial function (maybe the problem comes from this one ?):
binomialCoef :: Int -> Int -> Int
binomialCoef n 1 = n
binomialCoef n k = factorial n `div`
((factorial k) * factorial (n - k))
(…) realized my factorial function returns negative numbers starting at 21!, and I can't figure out why.
Because an Int has a fixed number of bits. An Int should at least represent all numbers between -2-29 and 229-1, and on a 64-bit system, typically it will represent numbers between -2-63 and 263-1, but regardless what bounds it represents, it will eventually run out of bits to represent such number.
You can work with Integer to represent arbitrary large numbers:
factorial :: Integer -> Integer
factorial 0 = 1
factorial 1 = 1
factorial num = num * factorial (num-1)
For example:
Prelude> factorial 21
51090942171709440000
Prelude> factorial 22
1124000727777607680000
The binomial coefficient is where ln(gamma) really shines:
Bi(n, k) = n!/(k!*(n-k)!)
Taking the natural log of both sides:
ln(Bi(n, k)) = ln(n!) - ln(k!) - ln((n-k)!)
But
gamma(n) = (n-1)!
Or
gamma(n+1) = n!
Substituting
ln(Bi(n, k)) = lngamma(n+1) - lngamma(k+1) -lngamma(n-k+1)
Taking the exponential of both sides gives the final result:
Bi(n, k) = exp(lngamma(n+1) - lngamma(k+1) - lngamma(n-k+1))
There's a Haskell implementation. I haven't looked at it, but it should return a Double instead of an Integer. You won't have overflow problems because of that fact. It'll also be better behaved because you will be subtracting logarithms instead of dividing a large numerator by a large product in the denominator.
Of course best way to avoid integer overflow and wrap-around while calculating a big factorial is not to calculate the factorial in the first place. Instead, since
factorial n = product [1..n]
keeping [1..n] as the representation of the factorial of n is as good -- or even much better -- as calculating the actual number. Postponing an action until absolutely unavoidable we get to pre-optimize it before post-calculating:
bincoef :: Int -> Int -> Int
bincoef n k = factorial n `div`
((factorial k) * factorial (n - k))
= product [1 .. n] `div`
(product [1 .. k] * product [1 .. n-k])
= product [n-k+1 .. n] `div`
product [1 .. k]
= foldl' g 1 $ zip [n, n-1 .. n-k+1] [1 .. k]
where g !acc (a,b) = (acc * a) `div` b
So now,
> mapM_ (\n -> print $ map (bincoef n) [5,10..n]) [20,30..60]
[15504,184756,15504,1]
[142506,30045015,155117520,30045015,142506,1]
[658008,847660528,40225345056,137846528820,40225345056,847660528,658008,1]
[2118760,10272278170,2250829575120,47129212243960,126410606437752,47129212243960,
2250829575120,10272278170,2118760,1]
[5461512,75394027566,53194089192720,4191844505805495,51915437974328292,1182645815
64861424,51915437974328292,4191844505805495,53194089192720,75394027566,5461512,1]
> head . filter (not . snd) $ map (\n -> (n, all (> 0) $ map (bincoef n) [1..n])) [1..]
(62,False)
the Int wrap-around error makes its first appearance at n=62. But it's still working at n=60, and we can see there are more than 16 digits in those numbers, so no Double-based calculation has a hope of working correctly, there.
To get into yet higher ranges still with the Int-based operations only, the next logical step is keeping the lists of integers as originally proposed, or better yet as their prime factorizations which are easy to multiply and divide; but at that point we'd be getting pretty close to re-implementing the bignum arithmetic ourselves, so might as well just use the simple Integer-based code,
bc :: Integer -> Integer -> Integer
bc n k = product [n-k+1 .. n] `div` product [1 .. k]
which "just works".
> bc 600 199
124988418115780688528958442419612410733294315465732363826979722360319899409241320138
666379143574138790334901309769571503484430553926248548697640619977793300443439200
I'm trying to define an is_prime function in Haskell. Can anyone point out the issue with the use of the any function?
In addition, I know that the below code is naïve, but I am learning the language so starting with babysteps.
is_prime 0 = False
is_prime 1 = False
is_prime 2 = True
is_prime n = any [n `mod` k == 0 | k <- [2.. sqrt n]]
Type of any is (a -> Bool) -> [a] -> Bool, so it accepts a predicate and a collection. So you should rewrite your last case as for instance
is_prime n = not $ any (\k -> n `mod` k /= 0)
[2 .. ceiling $ sqrt $ fromIntegral n]
fromIntegral is necessary because sqrt's type is Floating a => a -> a while your n is an integer. Subsequently, without ceiling the second argument of any would be Floating t => [t]. This would break, as calling mod, whose type is Integral a => a -> a -> a, on non-integral types is illegal.
If you'd like to look for some other implementations, I can recommend for example this discussion.
The accepted answer is, to my mind, incorrect as the is_prime function actually returns False if n is a prime, and here's why.
any function data returns True as soon as it encounters such an element in data that function data is True.
\k -> mod n k /= 0 returns True if applied to a number that does not divide some constant n.
thus, any returns True if there is a number in the given list that does not divide the number n we want to check for primality and False if there is one.
so, is_prime returns True for any number that is divisible by any number in the list [2 .. ceiling $ sqrt $ fromIntegral n], for example, 4 which clearly is not a prime.
With that said, the correct solution should look like this:
is_prime n = not $ any (\k -> n `mod` k == 0) [2 .. ceiling $ sqrt $ fromIntegral n]
This is because a number n is prime if it's not a multiple of any number between 2 and sqrt n.
I want to list all integers that divide n. This is a homework question. So far I have done this.
divisors :: Int -> [Int]
divisors n | n < 1 = []
| otherwise = filter (\n -> n `mod` x == 0) [1..n]
where x = [1..n]
I know this is wrong, but I am not getting the right filter predicate. I don't know how the syntax is for doing this. and ofcourse I cannot use n mod n since that is just lists all elements 1 to n.
You want to check if mod n k == 0 for each k from 1 to n. The n is fixed (the argument of divisors) and the k varies, i.e. that is what should be the argument of the lambda expression
| otherwise = filter (\k -> n `mod` k == 0) [1 .. n]
I don't know what you are trying to do, but the type of mod is
mod :: Integral a => a -> a -> a
You call it with an Integral argument and a list of integral arguments.
[Disclaimer] I am very new to Haskell (and any FPL for that matter), just started learning today by reading YAHT. So my code might look "funny". Any help to improve the coding style would be appreciated as well.
I was trying to write a function in Haskell that generates a list with series 1 to n for a given value of n, starting with +1 and toggling the sign first after 1 number, then 2, then 3 and so on.
e.g. series 16 should produce [1,-2,-3,4,5,6,-7,-8,-9,-10,11,12,13,14,15,-16] (1 positive, 2 negative, 3 positive, 4 negative, ...).
I found that the sign changes after each triangular number, which equals the sum of first few natural numbers.
So I wrote this code:
module Test
where
--It accepts n and k, prints numbers 1 to n, starting with +1 and toggling their sign after each triangular number
series 0 = []
series n =
if isTriangular n
then series (getPrevTri n (n-1)) ++ getSeries (odd (n + (getPrevTri n (n-1)))) ((getPrevTri n (n-1)) + 1) (n - (getPrevTri n (n-1)))
else series (getPrevTri n (n-1)) ++ getSeries (odd ((getNextTri n (n+1)) + (getPrevTri n (n-1)))) ((getPrevTri n (n-1)) + 1) (n - (getPrevTri n (n-1)))
--The sign is negative for those numbers which follow an odd triangular number AND the triangular number previous to it is even
--OR an even number AND the triangular number previous to it is odd.
getSeries sign start 0 = []
getSeries sign start n =
if sign == True
then [start] ++ getSeries True (start+1) (n-1)
else [-start] ++ getSeries False (start+1) (n-1)
--Checks whether n is a triangular number or not
isTriangular 0 = False
isTriangular n =
checkSum n 1
--Checks whether n is equal to sum of first few natural numbers, starting from k
checkSum n 0 = False
checkSum n k =
if n == (k * k + k)/ 2
then True
else if n > (k * k + k)/ 2
then checkSum n (k+1)
else False
--Gets the triangular number just smaller than n, descending from k
getPrevTri 0 k = 0
getPrevTri n k =
if k <= n
then if isTriangular k
then truncate k
else getPrevTri n (k-1)
else 0
--Gets the triangular number just greater than n, starting from k
getNextTri 0 k = 1
getNextTri n k =
if k >= n
then if isTriangular k
then truncate k
else getNextTri n (k+1)
else 0
I had to add a call to "truncate" in "getPrevTri" and "gerNextTri" since it started producing fractional numbers. But still I'm getting this error:
*Test> :load "Test.hs"
[1 of 1] Compiling Test ( Test.hs, interpreted )
Ok, modules loaded: Test.
*Test> series 16
<interactive>:1:0:
Ambiguous type variable `t' in the constraints:
`Integral t' arising from a use of `series' at <interactive>:1:0-8
`RealFrac t' arising from a use of `series' at <interactive>:1:0-8
Probable fix: add a type signature that fixes these type variable(s)
*Test>
Could someone explain what is the source of this error?
And what does surprise me is that when I tried to debug this code, I modified it to http://pastebin.ca/1932564 which produced the similar error.
And then to http://pastebin.ca/1932556 and it surprisingly caused no error.
(Please find the output at the end of the respective posts.)
What I infer from it is that a call to
isTriangular n
causes a type error in
odd n
How is it possible when Haskell is a "pure" FPL and in which functions do not have any side effects?
I used GHCi, version 6.12.3 for these codes, on a Windows 7 x64 machine.
There is no numerical type which implements both Integral (forced by odd) and RealFrac (forced by (/)). (These are typeclasses, if you don't know what I'm talking about, just wait until your tutorial shows about this)
You may replace either / by div or do an explicit cast via fromIntegral or similar. You may also do something like x/2 == 1 instead of odd x.
Edit: In your second pastebin file, you did the conversions via truncate, which is also possible.
Haskell strength is it's strong typing system, allowing you to do less programming errors but also involves the problem of having strange problem at obvious places. I would generally suggest you to provide type-informations at least at toplevel functions. (like myFunc :: Int -> Integer). This improves both readability and safety, as the compiler prompts you suddently if something went wrong. In ghci, you can easily find out about type informations via the :t command:
ghci> :t odd
odd :: (Integral a) => a -> Bool
Please notice, that you have to wrap parantheses around infix functions when using this:
ghci> :t ($)
($) :: (a -> b) -> a -> b
Because FUZxxI already gave you an answer you were looking for I will show you how your problem can be solved easier and a lot shorter. Just for information.
How would you solve your problem in your head? First, you have to 'generate' sequence containing [1,2,2,3,3,3,4,4,4,4 ... ] just to know where to change sign. That sequence, expressed in Haskell notation, would be -
numbers = concatMap (\x -> replicate x x) [1..]
Then you have to 'combine' each number of this sequence with corresponding number from sequence from 1 to n to give it proper sign - that would be -
series n = zipWith (\a b -> a*(-1)^(b `mod` 2 + 1)) [1..n] numbers
Well, and that's it. You have the solution. You can even express it as one-liner without using numbers variable. But i consider it less readable.