Let's take out the last line separately:
cycle xs = xs' where xs' = xs ++ xs'
Now, let's try to reduce it:
cycle xs = xs ++ (xs ++ (xs ++ (xs ++ ...)))
You can see that it expands infinitely. But note that this is not how expressions get reduced in Haskell. Expressions will be reduced to WHNF when it's demanded. So, let's demand some values from cycle
function:
ghci > take 1 $ cycle [1..]
[1]
This is how take
function is implemented:
take n _ | n <= 0 = []
take _ [] = []
take n (x:xs) = x : take (n-1) xs
Now, because of pattern matching - the value n
will be evaluated first. Since it is already in normal form, no further reduction needs to be done and it will be checked if it is less than or equal to zero. Since the condition fails, it will move on to the second condition. Here, it's second argument will be checked to see if it's equal to []
. As usual, haskell will evaluate it to WHNF which will be 1:_
. Here _
represents thunk. Now the whole expression will be reduced to 1:take 0 _
. Since this value has to be printed in ghci, the whole 1:take 0 _
will be reduced again. Following the similar steps like above again, we will get 1:[]
which reduces to [1]
.
Hence cycle [1,2,3]
will get reduced to WHNF in the form (1:xs)
and will be ultimately reduced to [1]
. But if the cycle function, itself is strict in it's implementation, then it will just go into an infinite loop:
cycle :: NFData a => [a] -> [a]
cycle [] = []
cycle xs = let xs' = xs ++ xs'
in deepseq xs xs'
You can test that in ghci:
ghci > take 1 $ cycle [1..]
^CInterrupted.