Если все в порядке, чтобы получить результирующий список в обратном порядке, вы можете воспользоваться ленью Хаскелла и вернуть список по мере его вычисления, вместо того, чтобы передавать его рекурсивно в качестве накопительного аргумента.Это не только позволяет вам потреблять и распечатывать список во время его вычисления (тем самым устраняя одну утечку места), вы также можете принять решение о том, сколько элементов вы хотите получить из intersect
:
{-# LANGUAGE BangPatterns #-}
intersect n k !z s
| x == y = f : intersect (n+1) (k+1) (z+1) (z+s)
| x < y = intersect (n+1) k (z+1) s
| otherwise = intersect n (k+1) z s
where x = (2*n*n) + 4 * n
y = (k * k + k )
f = (z, (x `div` 2), (z+s))
p = intersect 1 1 1 0
main = do
putStrLn (unlines (map show (take 23 p)))
Как отметил Дон, мы должны быть осторожны, чтобы накапливающиеся аргументы оценивались своевременно, а не накапливали большие громы.Делая аргумент z
строгим, мы гарантируем, что все аргументы будут востребованы.
Выводя по одному элементу на строку, мы можем наблюдать за полученным результатом:
$ ghc -O2 intersect.hs && ./intersect
[1 of 1] Compiling Main ( intersect.hs, intersect.o )
Linking intersect ...
(1,3,1)
(3,15,4)
(10,120,14)
(22,528,36)
(63,4095,99)
(133,17955,232)
(372,139128,604)
(780,609960,1384)
...