В Haskell, в чем разница между использованием takeWhile или «обычным» неравенством в понимании этого списка?
Я пытаюсь выучить меня на Haskell (для хорошего блага), и одна из многих разных вещей, которые я делаю, - это попытаться решить некоторые проблемы Project Euler, пока я иду, чтобы проверить свои способности.
Выполняя некоторые задачи, основанные на Фибоначчи, я наткнулся на и начал играть с рекурсивной версией бесконечного списка последовательности Фибоначчи:
fibs = 1 : 2 : zipWith (+) fibs (tail fibs)
Для одной из задач PE мне нужно было извлечь подпоследовательность четных чисел Фибоначчи меньше, чем 4 000 000. Я решил сделать это с пониманием списка, и, играя с кодом, я наткнулся на то, чего не совсем понимаю; Я предполагаю, что это мое слабое понимание ленивой схемы оценки Haskell, которая усложняет ситуацию.
Следующее понимание работает просто отлично:
[x | x <- takeWhile (<= 4000000) fibs, even x]
Следующее понимание вращается навсегда; поэтому я прошел и вернул вывод в stdout, и пока он останавливается в правильном месте, кажется, что он продолжает вычислять рекурсивно определенный список навсегда, не заканчивая после достижения ограниченного значения; указывает на то, что последний элемент в списке печатается через запятую, но никаких дополнительных элементов списка или закрывающей квадратной скобки нет:
[x | x <- fibs, x <= 4000000, even x]
Так в чем же секретный соус, используемый различными функциями, которые хорошо работают с бесконечными списками?