Haskell Functional Programming – How Does ‘repeat x = x:repeat x’ Return a List

functional programminghaskell

This is supposed to return an infinite list of x's. However a list is created using an element, then the operator ':' and then a list.

The recursive definition of repeat' x = x:repeat' x seems to never get to the point where an actual list is created as it seams to continuously add singular elements (where?), doing something like x:x:x:x:...

Best Answer

Probably your confusion comes from the fact that you are used to eager evaluation, whereas Haskell uses lazy evaluation.

For example, if you were to use the definition

repeat' x = x : repeat' x

to evaluate the expression repeat' 10 eagerly, then you would get

repeat' 10                ==>
10 : repeat' 10           ==>
10 : 10 : repeat' 10      ==>
10 : 10 : 10 : repeat' 10 ==>
...

and this would loop forever.

With lazy evaluation it is different. If you have the expression repeat' 10 in a certain context, this is not evaluated until the result of repeat' 10 is required.

As soon as you take values from the list, the above steps are executed, but only as many of them get executed as requested.

So, in Haskell applying your function to some value does not create an infinite data structure that is completely loaded in memory at some point in time: this is impossible because there is only a finite amount of memory and a computation that terminates can only take a finite amount of time. It rather creates a program from which you can pull any finite number of elements, i.e. any finite prefix of the infinite list.

Note that the finite prefix is not represented as a plain list

10 : 10 : 10 : []

but as a term like

10 : 10 : 10 : repeat' 10

So, suppose you want to compute with a finite list, e.g. take 2 [1, 2, 3]:

take 2 (1 : 2 : 3 : []) ==>
1 : take 1 (2 : 3 : []) ==>
1 : 2 : take 0 (3 : []) ==>
1 : 2 : []

Now, the same but with your infinite list:

take 2 (repeat' 10)           ==> -- repeat' x = x : repeat' x
take 2 (10 : repeat' 10)      ==> -- take n (x : xs) = x : take (n - 1) xs
10 : take 1 (repeat' 10)      ==> -- repeat' x = x : repeat' x
10 : take 1 (10 : repeat' 10) ==> -- take n (x : xs) = x : take (n - 1) xs
10 : 10 : take 0 (repeat' 10) ==> -- take 0 _        = []
10 : 10 : []