В 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]
Итак, что же такое секретный соус, используемый различными функциями, которые хорошо играют с бесконечными списками?
Ответы
Ответ 1
Функция takeWhile
сохраняет элементы входного списка до тех пор, пока не достигнет первого элемента, который не удовлетворяет предикату, а затем он остановится. Пока существует хотя бы один элемент, который не удовлетворяет предикату, takeWhile
превращает бесконечные списки в конечные списки.
Ваше первое выражение говорит
Продолжайте принимать элементы этого бесконечного списка, пока не найдете более 4 000 000, а затем остановитесь. Включите каждый элемент в выход, если он даже.
Второе выражение говорит
Продолжайте принимать элементы этого бесконечного списка. Включите каждый элемент в выход, если он меньше или равен 4,000,000, и даже.
Когда вы наблюдаете вывод, который вешает навсегда, функция на деле вырабатывает больше чисел фибоначчи и проверяет, меньше ли они или равна 4 000 000. Ни один из них, поэтому ничто не печатается на экране, но функция не знает, что она не будет сталкиваться с небольшим числом немного дальше по списку, поэтому она должна продолжать проверять.