Этот бит магии работает из-за лени haskells. Как вы, возможно, знаете, Haskell оценивает значение при необходимости, а не при определении. Таким образом, это работает, если вам не нужно вводить значение напрямую или, возможно, позже.
rec
реализовано с использованием функции loop
ArrowLoop
. Это определяется следующим образом:
class Arrow a => ArrowLoop a where
loop :: a (b,d) (c,d) -> a b c
instance ArrowLoop (->) where
loop f b = let (c,d) = f (b,d) in c
Вы можете видеть: Выход просто возвращается как вход. Он будет рассчитан только один раз, потому что Haskell оценит d
только тогда, когда это необходимо.
Вот пример того, как напрямую использовать комбинатор loop
. Эта функция вычисляет все полномочия своего аргумента:
powers = loop $ \(x,l) -> (l,x:map(*x)l)
(Вы могли бы также написать это так: powers x = fix $ (x :) . map (*x)
)
Как это работает? Ну, бесконечный список способностей находится в аргументе l
. Оценка выглядит так:
powers = loop $ \(x,l) -> (l,x:map(*x)l) ==>
powers b = let (c,d) = (\(x,l) -> (l,x:map(*x)l)) (b,d) in c ==>
powers b = let (c,d) = (d,b:map(*b)d) in d ==> -- Now we apply 2 as an argument
powers 2 = let (c,d) = (d,2:map(*2)d) in d ==>
= let (c,(2:d)) = (d,2:map(*2)d) in c ==>
= let (c,(2:4:d)) = ((2:d),2:map(*2)(2:d)) in c ==>
= let (c,(2:4:8:d)) = ((2:4:d),2:map(*2)(2:4:d)) in ==> -- and so on