Int -> Integer: type conversation misunderstanding - haskell

Here is my code for the calculating fibonacci numbers:
f' :: (Int -> Int) -> Int -> Int
f' mf 0 = 0
f' mf 1 = 1
f' mf n = mf(n - 2) + mf(n - 1)
f'_list :: [Int]
f'_list = map (f' faster_f') [0..]
faster_f' :: Int -> Int
faster_f' n = f'_list !! n
It works fine while 'n' is small. To resolve the problem with big numbers I would like convert Int-type to Integer:
f' :: (Integer -> Integer) -> Integer -> Integer
f' mf 0 = 0
f' mf 1 = 1
f' mf n = mf(n - 2) + mf(n - 1)
f'_list :: [Integer]
f'_list = map (f' faster_f') [0..]
faster_f' :: Integer -> Integer
faster_f' n = f'_list !! n
With this code I get the error:
Couldn't match expected type `Int' with actual type `Integer'
In the second argument of `(!!)', namely `n'
In the expression: f'_list !! n
In an equation for `faster_f'': faster_f' n = f'_list !! n
Well, I have understood correctly the index of element in the list can not be Integer-type.
OK:
f' :: (Integer -> Integer) -> Integer -> Integer
f' mf 0 = 0
f' mf 1 = 1
f' mf n = mf(n - 2) + mf(n - 1)
f'_list :: [Integer]
f'_list = map (f' faster_f') [0..]
faster_f' :: **Int** -> Integer
faster_f' n = f'_list !! n
But now I get the error:
Couldn't match expected type Integer' with actual typeInt'
Expected type: Integer -> Integer
Actual type: Int -> Integer
In the first argument of `f'', namely `faster_f''
In the first argument of `map', namely `(f' faster_f')'
Why? And how can I fix it?

The easiest way is to make your arguments Int (as they are indexes of Fibonacci numbers, not the numbers themselve), and use Integer just for the output:
f' :: (Int -> Integer) -> Int -> Integer
f' mf 0 = 0
f' mf 1 = 1
f' mf n = mf(n - 2) + mf(n - 1)
f'_list :: [Integer]
f'_list = map (f' faster_f') [0..]
faster_f' :: Int -> Integer
faster_f' n = f'_list !! n
Of course now you can't address Fibonacci numbers with an index outside the Int range, but practically you'll run out of space and time much, much, much sooner.
By the way, if you need a list of fibs, the "usual" implementation is
fibs :: [Integer]
fibs = 0 : scanl (+) 1 fibs
If you need just certain values, there is a fast calculation method similar to fast exponentiation using these formulas:
f(2n) = (2*f(n-1) + f(n)) * f(n)
f(2n-1) = f(n)² + f(n-1)²

Why?
Because f' expects an Integer -> Integer function, but you're sending it faster_f', which is an Int -> Integer function.
And how can I fix it?
Probably the easiest way is to use genericIndex (from Data.List) instead of (!!).

Integer is the infinite type of Int, (Int is only guaranteed to cover the range from -2^29 to 2^29-1, but in most implementations it's the full 32 or 64-bit type). That's why you get the first error. The second error you get because (!!) is a function that takes an list and an Int
(!!) :: [a] -> Int -> a
There are a lot of other (and maybe easier) ways to calculate the Fibonacci numbers. Here is one example that returns a list of all Fibonacci numbers to the specified. The first call is done by fibCall
fib :: Integer -> Integer -> Integer -> [Integer] -> [Integer]
fib 0 _ _ l = l
fib n a b l = fib (n-1) b (a+b) (a:l)
fibCall :: Integer -> [Integer]
fibCall n = n 1 1 []
If you just want the nth Fibonacci number, change [Integer] to Integer and (a:l) to a.

Related

How can I make this code to work with the Integer- > Int type signature?

This code is working with the Int- > [Int] type signature, but I have to solve it with Integer -> [Int] type signature. What do I have to change to make it work?
toBin :: Int -> [Int]
toBin n
| n == 0 = []
toBin n = [n `mod` 2] ++ toBin (n `div` 2)
You can use fromIntegral :: (Integral a, Num b) => a -> b to convert an Integer (or any Integral type) to an Int (or any Num type):
toBin :: Integer -> [Int]
toBin 0 = []
toBin n = [fromIntegral (n `mod` 2)] ++ toBin (n `div` 2)
If n is an Integer, than n `mod` `2 is an Integer as well. We can not use n `mod` 2 as element of a list, since the return type is [Int], so a list of Ints. We thus need to convert the Integer to an Int such that the type of the elements is correct, and we can convert an Integer to the corresponding Int (given the Integer can be represented by an Int) with fromIntegral.

Breaking out of If-Then when a certain requirement is met in Haskell

I am given the assignment of coding a hailstone sequence in Haskell. I must be given an integer and create a list of integers ending with the last number 1, eg.
-- > hailstone 4
-- [4,2,1]
-- > hailstone 6
-- [6,3,10,5,16,8,4,2,1]
-- > hailstone 7
-- [7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1]
My answer should have just one 1 at the end, however I do not know how to break out of the loop once reaching 1.
hailstone :: Integer -> [Integer]
hailstone = takeWhile (>=1) . (iterate collatz)
where collatz n = if n == 1
then 1
else if even n
then n `div` 2
else 3*n+1
I end up with infinite 1's at the end of this. How can I fix this?
You can use a function like takeUntil :: (a -> Bool) -> [a] -> [a] from the utility-ht package [hackage]. This function will:
Take all elements until one matches. The matching element is returned, too. This is the key difference to takeWhile (not . p). It holds takeUntil p xs == fst (breakAfter p xs).
So we can use that to include the 1:
import Data.List.HT(takeUntil)
hailstone :: Integer -> [Integer]
hailstone = takeUntil (== 1) . iterate collatz
where collatz 1 = 1
collatz n | even n = div n 2
| otherwise = 3 * n + 1
or we can implment takeUntil ourself:
takeUntil :: (a -> Bool) -> [a] -> [a]
takeUntil p = go
where go [] = []
go (x:xs) | p x = [x]
| otherwise = x : go xs
or with a fold:
takeUntil :: (a -> Bool) -> [a] -> [a]
takeUntil p = foldr (\x y -> x : if p x then [] else y) []
For negative numbers, the collatz can get stuck in an infinite loop:
Prelude> hailstone (-7)
[-7,-20,-10,-5,-14,-7,-20,-10,-5,-14,-7,-20,-10,-5,-14,-7,-20,-10,-5,-14,
We thus might want to change the condition for all numbers less than or equal to 1:
hailstone :: Integer -> [Integer]
hailstone = takeUntil (<= 1) . iterate collatz
where collatz 1 = 1
collatz n | even n = div n 2
| otherwise = 3 * n + 1
All this use of takeUntil, iterate, breaking out has a very imperative feel for me (do something with the numbers until you reach 1 - and then how the hell do I stop? what is the Haskell equivalent of a break statement.....?)
There is nothing wrong with that, and it wil work eventually, but when using Haskell, is often better to think a bit more declaratively: the tail of a hailstone sequence (other than [1]) is another (shorter) hailstone sequence, so hailstone n = n : hailstone (f n) for some f
Thus:
hailstone n
| n == 1 = [1]
| even n = n : hailstone (n `div` 2)
| otherwise = n : hailstone (3*n + 1)
The sole classic library function that seems to offer some hope is unfoldr. It uses the Maybe monad, and returning Nothing is what stops the recursion.
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
You have to pick the proper function argument:
import Data.List
hailstone :: Integer -> [Integer]
hailstone n =
let next nn = if (even nn) then (div nn 2) else (3*nn+1)
unfn nn = if (nn==1) then Nothing else let nx = next nn in Just (nx,nx)
in
n : (unfoldr unfn n)
main = do
putStrLn $ "hailstone 7 is: " ++ show (hailstone 7)
That way, the stopping criterion is clearly separated from the successor function.

Excel column to Int and vice-versa - improvements sought

In the code below, I am happy with the functionality i.e. the code produces the output that I expect. However, comparing the length of toCol to toInt - I am interested in knowing if you could offer something to trim it (i.e. toCol ) down. Many thanks!
-- given a spreadsheet column as a string
-- returns integer giving the position of the column
-- ex:
-- toInt "A" = 1
-- toInt "XFD" = 16384
toInt :: String -> Int
toInt = foldl fn 0
where
fn = \a c -> 26*a + ((ord c)-64)
-- given a integer returns
-- the column to be found at that position as a [Char]
-- ex:
-- toCol 1 = "A"
-- toCol 16384 = "XFD"
toCol :: Int -> [Char]
toCol n = toCol' n []
where
toCol' 0 a = a
toCol' n a =
let r = mod n 26 in
case (r == 0) of
True -> toCol' (div (n-1) 26) ('Z':a)
False -> toCol' (div n 26) (chr(r + 64) : a)
Whenever you are building up a finite list recursively, think about unfoldr :: (b -> Maybe (a, b)) -> b -> [a] from Data.List (although because it unfolds from the wrong direction, we end up needing to reverse the list too). The syntax extension MultiWayIf also helps make things nicer.
{-# LANGUAGE MultiWayIf #-}
toCol :: Int -> [Char]
toCol = reverse . unfoldr (\n -> let r = n `mod` 26 in
if | n == 0 -> Nothing
| r == 0 -> Just ('Z' , n-1 `div` 26)
| otherwise -> Just (chr (r + 64), n `div` 26))
Note that this also makes toCol point-free. If you would prefer to not have an extension enabled and prefer to pattern match, you can also do that:
toCol :: Int -> [Char]
toCol = reverse . unfoldr (\n -> case (n, n `mod` 26) of
(0, _) -> Nothing
(n, 0) -> Just ('Z' , n-1 `div` 26)
(n, r) -> Just (chr (r + 64), n `div` 26))

find a Float value not over another value haskell

I have to find a height that's not taller than a given value. I have found code that does it for a list of integers. But I need it to accept a float value i.e. countElems :: Float -> Heights -> Int. I know I have to use fromIntegral to allow a Float value but I don't know how to implement it. This is what I have so far:
countElems :: Int -> [Int] -> Int
countElems n (x:xs) = fromEnum (n < x) + countElems n xs
countElems _ [] = 0
Just edit countElems type annotation to accept any ordered type:
countElems :: Ord a => a -> [a] -> Int
countElems n (x:xs) = fromEnum (n < x) + countElems n xs
countElems _ [] = 0
Now it works both for Int and Float and for every instance of Ord type class.
Actually, it's an actual type of countElems which compiler infers. Your version is restricted only for a = Float.
I got it to work using:
countElems :: Float -> [Float] -> Int
countElems _ [] = 0
countElems n (x:xs)
| n < x = 1 + (tallerthan n xs)
| otherwise = tallerthan n xs

type constructor or class error

dreiNplusEins :: Integer -> [Integer]
dreiNplusEins n = if n == 1 then [1] else if n `mod` 2 == 0 then
[n] ++ dreiNplusEins (n `div` 2)
else
[n] ++ dreiNplusEins (n * 3 + 1)
maxZyklus :: UntereGrenze -> ObereGrenze -> (UntereGrenze,ObereGrenze,MaxZyklaenge)
maxZyklus m n = if m > n then (m,n,0) else if m == n then
(m,n,length(dreiNplusEins m))
else
(m,n,0)
type UntereGrenze = Integer
type ObereGrenze = Integer
type MaxZykLaenge = Integer
this is my program and this gives error as Not in scope: type constructor or class `MaxZyklaenge' how can i fix it ?
You have a typo in the type name:
In the type signature of maxZyklus you write MaxZyklaenge (lower case l), but in the type definition you write MayZykLaenge (capital L).
Even if you fix the typo you'll still get an error, since length returns an Int where you need an Integer. The following is one way to fix this (I've also rewritten your code to use guards):
import Data.List (genericLength)
dreiNplusEins :: Integer -> [Integer]
dreiNplusEins 1 = [1]
dreiNplusEins n
| n `mod` 2 == 0 = n : dreiNplusEins (n `div` 2)
| otherwise = n : dreiNplusEins (n * 3 + 1)
maxZyklus :: UntereGrenze -> ObereGrenze -> (UntereGrenze, ObereGrenze, MaxZyklaenge)
maxZyklus m n
| m == n = (m, n, genericLength $ dreiNplusEins m)
| otherwise = (m, n, 0)
type UntereGrenze = Integer
type ObereGrenze = Integer
type MaxZyklaenge = Integer
You could also use fromIntegral . length if you don't want the extra import, but I personally think genericLength is a little clearer.
Also, if you're interested, here's an arguably nicer way to write the first function:
dreiNplusEins :: Integer -> [Integer]
dreiNplusEins = (++[1]) . takeWhile (/=1) . iterate f
where
f n | even n = n `div` 2
| otherwise = n * 3 + 1
This just says "iteratively apply f until you hit a 1, and then tack a 1 on the end".
To find the number in a given range that produces the longest chain, you can use the following function:
longestBetween :: (Enum a, Integral b) => (a -> [b]) -> (a, a) -> (a, b)
longestBetween f (m, n)
= maximumBy (comparing snd)
. zip [m..n] $ map (genericLength . f) [m..n]
The first argument is the function that creates the list and the second is the range. The return value is a tuple containing the desired number in the range and the length of its list. Note that we need these additional imports:
import Data.List (genericLength, maximumBy)
import Data.Ord (comparing)
We can test as follows:
*Main> longestBetween dreiNplusEins (100, 1000)
(871,179)
Implementing the maxZyklus function you specify in the comments just takes a couple of minor changes at this point:
maxZyklus m n = (m, n, maximum $ map (genericLength . dreiNplusEins) [m..n])
maxZyklus 11 22 gives the desired (11, 22, 21).
Haskell is case sensitive.
In the type signature of maxZyklus:
... ,MaxZyklaenge)
-- # ^
But you have:
type MaxZykLaenge = Integer
-- # ^
It's defined as MaxZykLaenge (note the "L"), whereas you wrote the type as "MaxZyklaenge". Haskell is case-sensitive.

Resources