Este poco de magia funciona debido a la pereza de Haskell. Como sabrá, Haskell evalúa un valor cuando es necesario, no cuando está definido. Por lo tanto, esto funciona si no necesita el valor ingresado directamente, o tal vez más tarde.
rec
se implementa utilizando la función loop
de . Se define como sigue:
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
Puede ver: La salida simplemente se retroalimenta como entrada. Se calculará solo una vez, porque Haskell solo evaluará d
cuando sea necesario.
Aquí hay un ejemplo real de cómo usar el combinador loop
directamente. Esta función calcula todos los poderes de que el argumento de:
powers = loop $ \(x,l) -> (l,x:map(*x)l)
(También podrían escribir como este en su lugar: powers x = fix $ (x :) . map (*x)
)
¿Cómo funciona? Bueno, la lista infinita de poderes está en el argumento l
. La evaluación es el siguiente:
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
[En caso] (http://www.haskell.org/haskellwiki/Keywords#rec) alguien no ha oído hablar de 'rec' antes. –