Почему карта не требует строгости, тогда как zipWith? - PullRequest
5 голосов
/ 28 июня 2011

Существует две строгие версии функции zipWith:

1) Действительно строго, элементы списков l1 и l2 оцениваются, поэтому их блоки не занимают все пространство стека (код Дона Стюарта)

zipWith' f l1 l2 = [ f e1 e2 | (e1, e2) <- zipWith k l1 l2 ]
            where
                k x y = x `seq` y `seq` (x,y)

2) Не очень строго, попытайтесь форсировать оценку другим способом.

zipWith'' f l1 l2 = [ f e1 e2 | (e1, e2) <- zip (map (\x -> x `seq` x) l1) (map (\x -> x `seq` x) l2) ]

Вопрос: почему не получается эквивалентный код из 2-го примера, использующего map функция также строгая?

Ответы [ 2 ]

15 голосов
/ 28 июня 2011

Распространенная ошибка - использовать

x `seq` x

Что в точности эквивалентно

x

Отличное объяснение доступно в Пост Нила Митчелла о плохой строгости .

3 голосов
/ 28 июня 2011

Вместо тавтологического map можно использовать эту функцию для принудительного создания списка:

evl []     = []
evl (x:xs) = x `seq` (x:evl xs)
-- Cannot figure out how to do this with fold.

Тогда строгий zipWith равен

zipWith''' f xs ys = zipWith f (evl xs) (evl ys)
...