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.
Community
  • 1
  • 1
Zelphir Kaltstahl
  • 5,722
  • 10
  • 57
  • 86
  • There are much faster ways to perform the calculation. – dfeuer Feb 11 '16 at 05:38
  • @dfeuer kinda offtopic, but I am interested. Would you link me one? – Zelphir Kaltstahl Feb 11 '16 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. – dfeuer Feb 11 '16 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. – dfeuer Feb 11 '16 at 17:45
  • @dfeuer Sounds quite complex. And here I thought I had found a good and efficient solution :D – Zelphir Kaltstahl Feb 11 '16 at 17:54
  • Not so complex, really. See https://wiki.haskell.org/The_Fibonacci_sequence#Logarithmic_operation_implementations – dfeuer Feb 11 '16 at 18:05

1 Answers1

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
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380