2014-09-19 5 views
15

Сегодня, когда я работал над одним маленьким скриптом, я использовал foldl вместо foldl'. Я получил stack overflow, поэтому я импортировал Data.List (foldl') и был доволен этим. И это мой рабочий день по умолчанию с foldl. Просто используйте foldl', когда ленивая версия подходит для оценки.Практическое использование `foldl`

Real World Haskell говорит, что в большинстве случаев мы должны использовать foldl' вместо foldl. Foldr Foldl Foldl' говорит, что

Обычно выбор между foldr и foldl'.

...

Однако, если функция объединения ленива в качестве первого аргумента, foldl может счастливо возвращать результат, где foldl' ударяется исключением.

И данный пример:

(?) :: Int -> Int -> Int 
_ ? 0 = 0 
x ? y = x*y 

list :: [Int] 
list = [2, 3, undefined, 5, 0] 

okey = foldl (?) 1 list 

boom = foldl' (?) 1 list 

Ну, я извиняюсь, но это скорее академический, но интересный учебный пример. Поэтому я спрашиваю, есть ли пример практического использования foldl? Я имею в виду, когда мы не можем заменить foldl на foldl'.

P. S. Я знаю, трудно определить термин practical, но я надеюсь, что вы поймете, что я имею в виду.

P. P. S. Я понимаю, почему ленивый foldl по умолчанию в haskell. Я не прошу никого переместить гору и сделать строгую версию по умолчанию. Меня просто интересуют примеры исключительного использования функции foldl :)

P. P. P. S. S. Любое интересное использование foldl приветствуется.

+4

Вместо того чтобы просто избегать 'undefined', вы также можете использовать' foldl', чтобы избежать потенциально дорогостоящих операций. Если функция сгибания заканчивается на ранней стадии успешной операции, вы можете избежать выполнения дорогостоящих вычислений посредством лени. Там могут быть более понятные способы написания (моноиды приходят в голову), но складки могут быть приятными для оптимизации компилятора. – bheklilr

+0

Да, я думал об этом. Но не может представить себе хороший пример такой функции. – d12frosted

ответ

12

Вот более практичный пример использования классической наивной реализации Фибоначчи для моделирования дорогостоящих вычислений:

Тогда, если вы имели

> -- Turn on statistics for illustrative purposes 
> :set +s 
> foldl f maxBound $ map fib [30, 20, 15] 
987 
(0.02 secs, 0 bytes) 
> foldl' f maxBound $ map fib [30, 20, 15] 
987 
(4.54 secs, 409778880 bytes) 

Здесь мы имеем резкое различие в производительности во время выполнения между ленивыми и строгими версиями, с ленивой версией победы из-за оползнем. Конечно, ваши номера могут отличаться для вашего компьютера, но вы определенно заметите разницу в скорости выполнения. foldl' заставляет каждое вычисление происходить, а foldl - нет.Это также может быть полезно на что-то вроде

> foldl f maxBound $ map length [repeat 1, repeat 1, replicate 10 1] 
10 

В отличие от fib Например, это вычисление технически включает в себя основание, так как length $ repeat 1 никогда не закончит свои вычисления. Не имея обоих аргументов f, мы будем строго (как это делает foldl'), у нас есть программа, которая останавливается против той, которая никогда не будет.

+0

Разве вам не лучше делать это с помощью 'reverse', а затем' foldr'? Таким образом, вам не нужно обрабатывать весь список. –

+0

@TomEllis Я не говорю, что это лучший способ, просто это пример того, как foldl может быть лучшим выбором. – bheklilr

+0

Хорошо, спасибо за ваш ответ. Теперь у меня есть несколько интересных примеров использования 'foldl': D – d12frosted

5

Я могу думать об одном (хотя это может быть, что это дает хороший код только с оптимизирующий компилятор):

last = foldl (\_ x -> x) (error "emptyList") 

Это не будет иметь правильное поведение с foldl':

> foldl (\_ x -> x) (error "emptyList") [error "foo", "last"] 
"last" 
> foldl' (\_ x -> x) (error "emptyList") [error "foo", "last"] 
"*** Exception: foo 
+0

Ну, это действительно выглядит как '_? 0 = 0'. Но в любом случае спасибо за еще один пример. – d12frosted

Смежные вопросы