When we design a program, we can think in terms of input data and output data.

For instance, if we want to get the total of a bill, we want to sum a sequence of decimal numbers and return another number representing the total. In this case, the input data is a sequence of decimal numbers and the output data is a single number.

[Program] structure should be dictated by the structure of its input and output data streams. (Jackson 2002)

But there are two ways we can interpret this functionally.

Look at the type signature of foldr.

foldr :: (a -> b -> b) -> b -> [a] -> b

Note that [a] is fixed in a way that no other part of the type signature is - it has to be a list of type a. The output type is not fixed - b could be any type.

Because of these constraints, folds are input data-driven.

If we look at unfolds instead, we get:

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

In this case, the output data is fixed - it is always a list of type a. So unfolds are output data-driven.

It can be useful to note that we can often structure the same program in two ways - by the structure of the input or of the output.

(Read Gibbons 2021 for more.)