0

I know this question popped up before, but the answer in this question for some reason doesn't work for me. My example is the following code:

fiblist = 0 : 1 : (zipWith (+) fiblist (tail fiblist))

fib :: (Integral a) => a -> String
fib n
  | n < 10000 = show (fiblist !! n)
  | otherwise = error "The number is too high and the calculation might freeze your machine."

I am trying to convert the element at index n to a String, so that the function complies with its signature, but I get the following error:

MyLib.hs:63:34:
    Couldn't match expected type ‘Int’ with actual type ‘a’
      ‘a’ is a rigid type variable bound by
          the type signature for fib :: Integral a => a -> String
          at MyLib.hs:61:8
    Relevant bindings include
      n :: a (bound at MyLib.hs:62:5)
      fib :: a -> String (bound at MyLib.hs:62:1)
    In the second argument of ‘(!!)’, namely ‘n’
    In the first argument of ‘show’, namely ‘(fiblist !! n)’
Failed, modules loaded: none.

So how can I convert it?

Edit #1:

I am aware of the command line options +RTS -M256m -K256m and such, but they don't seem to work for this code, it still eats up almost all my memory, if n is too high. Different behavior for length of an infinite list, there the command line arguments work and stop the execution code.

Edit #2:

I found a way to import genericIndex:

import Data.List

which I guess is the same as shown on here.

Now when I use the following code:

fib :: (Integral a) => a -> String
fib n
  | n < 10000 = genericIndex fiblist n
  | otherwise = error "The number is too high and the calculation might freeze your machine."

I get the following error:

MyLib.hs:64:11:
    No instance for (Num String) arising from the literal ‘0’
    In the first argument of ‘(:)’, namely ‘0’
    In the expression: 0 : 1 : (zipWith (+) fiblist (tail fiblist))
    In an equation for ‘fiblist’:
        fiblist = 0 : 1 : (zipWith (+) fiblist (tail fiblist))
Failed, modules loaded: none.
6
  • There are much faster ways to perform the calculation. Commented Feb 11, 2016 at 5:38
  • @dfeuer kinda offtopic, but I am interested. Would you link me one? Commented Feb 11, 2016 at 14:44
  • There's a whole page of ways on the Haskell wiki somewhere. The big "aha!" one is to break up the sequence into pairs (1,1),(2,3),... and realize that you can get from each pair to the next by multiplying by the same matrix. Then since matrix multiplication is associative, you can use exponentiation by squaring to make it super-fast--O(log n) additions to get the nth element, if I'm not very much mistaken. Commented Feb 11, 2016 at 17:37
  • Note: you can "cheat" your way into exponentiation by squaring by making a bogus Num instance for your matrix type supporting only multiplication and fromInteger (which should give diagonal matrices). That'll let you use ^, which on GHC at least uses exponentiation by squaring. Commented Feb 11, 2016 at 17:45
  • @dfeuer Sounds quite complex. And here I thought I had found a good and efficient solution :D Commented Feb 11, 2016 at 17:54

1 Answer 1

2

Since you claim fib is polymorphic over all instance of Integral, the simplest fix is probably to switch from using (!!) to using genericIndex, which have these type signatures:

(!!)         ::               [a] -> Int -> a
genericIndex :: Integral i => [a] ->  i  -> a
Sign up to request clarification or add additional context in comments.

2 Comments

Updated my question.
@Zelphir You changed (!!) to genericIndex, but dropped the show for some reason!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.