How does Haskell instantly calculate this huge amount?

I am starting to learn Haskell, and one of the things that I love to do when I learn a new language is to make Euler Project problems as a complement to my basic reference material.

I came up with the following solution to the second problem of finding the sum of even Fibonacci numbers less than four million:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
f :: Integer -> Integer
f n =
  let evenFib = filter (\n -> n `mod` 2 == 0) fibs
  in sum (takeWhile (<n) evenFib)

This works great; f 4000000returns the correct answer. He does it instantly. Curiously, I began to print more and more ...

Prelude> f 40000000
19544084
Prelude> f 400000000000
478361013020
Prelude> f 40000000000000000000000000000000
13049874051046942401006156573274
Prelude> f 2370498572349582734598273495872349587234958723948752394857
2805750129675962215536656398462489370528480907433875715844

Each of these values ​​is returned immediately. I cannot guarantee the veracity of the last two answers because my implementations in other languages ​​do not work for large numbers.

, : ? ( )? , , ?

+4
3

, Haskell, , .

( 1,6 ), 40000000000000000000000000000000, , 100.

, 100 ( ), .

, , , Fibonacci :

fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)

, fib n fib (n-1), fib (n-2) fib n. fib (n-2), .

fib Haskell (, , ) :

fib 0 = 0
fib n = fib' 0 1 n

fib' _ curr 1 = curr
fib' last curr n = fib' curr (last+curr) (n-1)

, fib' , . , , , 0 : 1 : zipWith (+) fibs (tail fibs), , , , .

+7

.

:set +s ghci / . ​​

, , :

Prelude> :set +s
Prelude> :{
Prelude| fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Prelude| f :: Integer -> Integer
Prelude| f n =
Prelude|   let evenFib = filter (\n -> n `mod` 2 == 0) fibs
Prelude|   in sum (takeWhile (<n) evenFib)
Prelude| :}
(0.14 secs, 0 bytes)
Prelude> f 40000000
19544084
(0.02 secs, 83,440 bytes)
Prelude> f 40000000
19544084
(0.01 secs, 83,200 bytes)
Prelude> f 400000000000
478361013020
(0.01 secs, 94,800 bytes)
Prelude> f 40000000000000000000000000000000
13049874051046942401006156573274
(0.01 secs, 149,400 bytes)
Prelude> f 2370498572349582734598273495872349587234958723948752394857
2805750129675962215536656398462489370528480907433875715844
(0.01 secs, 225,488 bytes)

, , evenFib

Prelude> sequence_ $ map (putStrLn . show) $ take 20 $ filter ((== 0) . (flip mod 2)) $ fibs
0
2
8
34
144
610
2584
10946
46368
196418
832040
3524578
14930352
63245986
267914296
1134903170
4807526976
20365011074
86267571272
365435296162
(0.02 secs, 203,472 bytes)

, .

+4

, . , , .

, , , unfoldr , , , foldr1 . foldr1 takeWhile filter . , O (n).

fibs :: [Integer]
fibs = unfoldr (\(f,s) -> Just (f,(s,f+s))) (0,1)

sumEvenFibsUpto :: Integer -> Integer
sumEvenFibsUpto n =  foldr1 (\ x y -> if x < n then if x `rem` 2 == 0 then x + y
                                                                      else y
                                               else 0) fibs

*Main> sumEvenFibsUpto 2370498572349582734598273495872349587234958723948752394857
2805750129675962215536656398462489370528480907433875715844
(0.01 secs, 324,392 bytes)
+1

Source: https://habr.com/ru/post/1676795/


All Articles