52700.fb2 Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 160

Учебник по Haskell - читать онлайн бесплатно полную версию книги . Страница 160

[1 of 1] Compiling Strict

( Strict. hs, Strict. o )

Отметим наличие специальной функции применения, которая просит перед применением привести ар-

гумент к СЗНФ, эта функция определена в Prelude:

($! ) :: (a -> b) -> a -> b

f $! a = a ‘seq‘ f a

С этой функцией мы можем определить функцию sum так:

sum’ :: Num a => [a] -> a

sum’ = iter 0

where iter res []

= res

iter res (a:as)

= flip iter as $! res + a

Функции с хвостовой рекурсией

Определим функцию, которая не будет лениться при вычислении произведения чисел, мы назовём её

product’:

product’ :: Num a => [a] -> a

product’ = iter 1

where iter res []

= res

iter res (a:as)

= let res’ = res * a

in

res’ ‘seq‘ iter res’ as

Смотрите функция sum изменилась лишь в двух местах. Это говорит о том, что пора задуматься о том,

а нет ли такой общей функции, которая включает в себя и то и другое поведение. Такая функция есть и

называется она foldl’, вот её определение:

foldl’ :: (a -> b -> a) -> a -> [b] -> a

foldl’ op init = iter init

where iter res []

= res

iter res (a:as)

= let res’ = res ‘op‘ a

in

res’ ‘seq‘ iter res’ as

Мы вынесли в аргументы функции бинарную операцию и начальное значение. Всё остальное осталось

прежним. Эта функция живёт в модуле Data.List. Теперь мы можем определить функции sum’ и prod’:

148 | Глава 9: Редукция выражений

sum’

= foldl’ (+) 0

product’

= foldl’ (*) 1

Также в Prelude определена функция foldl. Она накапливает значения в аргументе, но без принуждения

вычислять промежуточные результаты:

foldl :: (a -> b -> a) -> a -> [b] -> a

foldl op init = iter init

where iter res []

= res

iter res (a:as)

= iter (res ‘op‘ a) as