To Infinity and Beyond!

We're at the end of January now, so this will be the last article on basic list utilities. For this last set of functions, we'll explore some items that are very helpful when you are using infinite lists in Haskell.

Infinite lists are kind of a cool construct because they only really exist due to Haskell's lazy evaluation mechanisms. Most other languages don't have them because eager evaluation would force you to use an infinite amount of space! But in Haskell, you only need to allocate space for the items in the list that actually get evaluated.

The two most basic functions for creating an infinite list are "repeat" and "cycle". The first makes an infinite number of the same element, while the second allows you to cycle through a specific series of elements.

repeat :: a -> [a]

cycle :: [a] -> [a]

But how exactly are these useful? For example, simply by trying to print them we'll create a mess of output that will make us force quit the program:

>> repeat 3
[3, 3, 3, 3, 3, ...
>> cycle [1, 2, 3, 4]
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, ...

Well one answer is to use take, which we learned about last time. We can "take" a specific number of a single element.

>> take 5 (repeat 3)
[3, 3, 3, 3, 3]

Infinite lists are also great in conjunction with zip, because this "shortens" the result to the size of the finite list. Suppose we want to match up a list with the index modulo 4:

>> let l1 = [5, 3, 1, -4, 6, 20]
>> zip l1 (cycle [0, 1, 2, 3])
[(5, 0), (3, 1) ,(1, 2) ,(-4, 3) ,(6, 0) ,(20, 1)]

One more way to generate an infinite list is to use iterate. This allows us to continually apply a function against a starting value. We start with a, and then the second element will apply the function once as f a, and then the next value will be f (f a), and so on.

iterate :: (a -> a) -> a -> [a]

One use case for this might be to calculate the value of an investment using compound interest. Let's say you start with $10,000 and you get 5% interest every year. How much will you have after 5 years?

>> take 6 (iterate (* 1.05) 10000.0)
[10000.0, 10500.0, 11025.0, 11576.25, 12155.06, 12762.82]

You can also use fairly simple addition functions with iterate. But you should also know that in most cases you can represent such an infinite list with a range!

>> take 5 (iterate (+3) 1)
[1, 4, 7, 10, 13]
>> take 5 [1,4..]
[1, 4, 7, 10, 13]

That's all for our exploration of basic list functions! We'll have a new topic next month, so subscribe to our monthly newsletter to stay on top of what we're studying! You can also sign up by downloading our free Beginners Checklist!

Previous
Previous

Classy Strings

Next
Next

Taking and Dropping