deniok: (пацифик)
deniok ([personal profile] deniok) wrote2014-10-31 08:16 pm

Куда прячется ленивость и как ее оттуда достать?

Мы привыкли, что правая свертка (foldr) хорошо заточена для работы с бесконечными списками:
> let mapPlusPi = foldr (\x xs -> (x+pi):xs) []
> head $ mapPlusPi [1..]
4.141592653589793
К сожалению, иногда возникают неприятности. Вот функция, которая берет список и выкидывает из него элементы стоящие на нечетных местах:
> let evenOnly = snd . foldr (\x (os,es) -> (x:es,os)) ([],[])
> evenOnly [1..10]
[2,4,6,8,10]
Только вот на бесконечном списке она ведет себя неподобающе
> head $ evenOnly [1..]
Interrupted.
Почему это происходит, и какие минимальные изменения можно в нее внести, чтобы восстановить утраченную работоспособность?

[identity profile] sassa-nf.livejournal.com 2014-10-31 07:49 pm (UTC)(link)
а, нутк, довольно странно это, конечно, но выходит, что pattern-match не может доказать, что он irrefutable, а потому должен быть strict.

Т.е. например вот здесь:

let bla = foldr(\x (y:t) -> x:t) [0]

понятно, что поскольку у списка есть два конструктора, то нужно убедиться, что y:t, а не []. А вот у тупля только один конструктор, так что, не ясно, что его останавливает лениво матчить.

[identity profile] voidex.livejournal.com 2014-10-31 08:00 pm (UTC)(link)
То, что помимо (,) у кортежа есть ещё один конструтор: _|_