I have written the following code which creates an infinite list of Fibonacci numbers:
fibs = 1:1:fib 1 1
where fib a b = a+b:fib b (a+b)
The foldl
and foldr
functions are list-consumers. As svenningsson's answer rightly points out, unfoldr
is a list-producer which is suitable for capturing the co-recursive structure of fibs
.
However, given that foldl
and foldr
are polymorphic in their return types, i.e. what they're producing by consuming a list, it is reasonable to ask whether they might be used to consume one list and produce another. Might any of these produced lists be infinite?
Looking at the definition of foldl
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f a [] = a
foldl f a (b : bs) = foldl f (f a b) bs
we see that for foldl
to produce anything at all, the list it consumes must be finite. Thus if foldl f a
produces infinite output, it is because a
is infinite or because f
sometimes performs infinite list generation.
It's a different story with foldr
foldr :: (b -> a -> a) -> a -> [b] -> a
foldr f a [] = a
foldr f a (b : bs) = f b (foldr f a bs)
which admits the lazy possibility that f
might generate some output for each b
consumed from the input. Operations like
map g = foldr (\ b gbs -> g b : gbs) [] -- golfers prefer ((:) . g)
stutter = foldr (\ x xxs -> x : x : xxs) []
producing a little bit of output for each input, deliver infinite output from infinite input.
A cheeky person can thus express any infinitary recursion as a non-recursive foldr
on an infinite list. E.g.,
foldr (\ _ fibs -> 1 : 1 : zipWith (+) fibs (tail fibs)) undefined [1..]
(Edit: or, for that matter
foldr (\_ fib a b -> a : fib b (a + b)) undefined [1..] 1 1
which is closer to the definition in the question.)
although this observation, whilst true, is hardly indicative of a healthy programming style.
You can use zipWith
to write your definition
fibonacci = 1:1:zipWith (+) fibonacci (tail fibonacci)
edit: Ok, I dont think you can use foldl or foldr to create infinite list. Not in any simple imaginable sense. If you look at the simple definition of foldl
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
foldl never returns until it has exhausted the whole list. So a simple example like
g = foldl f [] [1..]
where
f xs a = xs ++ [a]
> take 10 g
will not work even and it will loop on forever.
One way to avoid explicit recursion is to use fix to express the recursion as a fixed point.
import Data.Function (fix)
fibs = fix $ \l -> [1,1] ++ zipWith (+) l (tail l)
or in point-free style
import Data.Function (fix)
import Control.Monad.Instances
fibs = fix $ ([1,1] ++) . (zipWith (+) =<< tail)
I don't know if it's possible to create infinite lists with foldl
. You could perhaps solve this problem by using foldr
, but then you would have to create another list to fold over. What would that list be? There is nothing with the fibonacci numbers that suggest they are generated from some other list.
What you want instead is to use unfoldr
. It can be used to create lists instead of consuming them, as is the case for foldl
and foldr
. Here's how you would use unfoldr
to generate the infinite list of fibonacci numbers.
fib = unfoldr (\(a,b) -> Just (a,(b,a+b))) (1,1)
You can find unfoldr
in the module Data.List
in the base package.