2016-03-17 4 views
1

Задача состоит в том, чтобы использовать только одну сквозную перегородку, используя foldr или foldl. Я использую это решение:Получить список элементов, расположенных в четных положениях исходного списка

evenOnly = fst . foldr (\x (y1, y2) -> (y2, x:y1)) ([],[]) 

Довольно хорошо для конечных списков. Если я попробую evenOnly [1,2..], у меня получится неудача. Я знаю, что это из-за приостановленных каценций, но как я могу разделить список или как передать дополнительную информацию о позициях списка или что-то в вычислениях, которые начинаются в конце списка?

+0

Возможный дубликат поведения [foldl versus foldr с бесконечными списками] (http://stackoverflow.com/questions/3082324/foldl-versus-foldr-behavior-with-infinite-lists) – Bakuriu

+0

Ну, 'foldr' работает на бесконечные списки ** при условии **, что выполняемая функция достаточно ленивая. Ясно объяснено в [этом ответе] (http://stackoverflow.com/a/3085516/510937). Цитата: «** Если **' f' ленив во втором аргументе - например, конструктор данных - результат будет поэтапно ленивым, причем каждый шаг складки вычисляется только тогда, когда требуется какая-то часть результата он оценивается ». Функция, которую вы используете, всегда использует свой второй аргумент, поэтому она ведет себя «как' foldl' ». – Bakuriu

+0

Конечно. Я не имею в виду, что это единственное возможное решение с 'foldr'. Во всяком случае, на данный момент нельзя изобретать что-то более продвинутое. – BarbedWire

ответ

2

Вы можете использовать lazy pattern~(x1, y2):

> let evenOnly = fst . foldr (\x ~(y1, y2) -> (y2, x:y1)) ([],[]) 
> take 20 $ evenOnly [1..] 
[2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40] 

Это, по существу, такой же, как

> let evenOnly = fst . foldr (\x y -> (snd y, x:fst y)) ([],[]) 

, который имеет преимущество не принуждая конструктор пары слишком рано. То есть вышеописанная лямбда создаст конструктор (,) в своем выходе до, который требует y («рекурсивный» результат).

+0

Спасибо! Ты сделал мой день. – BarbedWire