What I would like to do is define a function like this:
[f 0, f f 0, f f f 0, f f f f 0, f f f f f 0..]
Or in other words, where each element is the last element that is run through a function.
I have tried a few times to get this working with ways similar to ways I have seen the Fibonacci sequence in Haskell, by calling the list with the first few elements pre-defined:
fib = 0 : 1 : zipWith (+) fib (tail fib)
ls = 0 : f 0 : f (last ls)
If I define f as a simple addOne function like so:
f = (+ 1)
I get this error:
<interactive>:124:5: error:
* Occurs check: cannot construct the infinite type: a ~ [a]
Expected type: [[a]]
Actual type: [a]
* In the expression: 0 : (f 0) : f (last y)
In an equation for `y': y = 0 : (f 0) : f (last y)
* Relevant bindings include
y :: [[a]] (bound at <interactive>:124:1)
How do I create a list that functions like this does?
The base case for numeric recursion usually consists of one or more specific numbers (often 0 or 1) for which the answer can be immediately given. The recursive case computes the result by calling the function recursively with a smaller argument and using the result in some manner to produce the final answer.
Recursion is important to Haskell because unlike imperative languages, you do computations in Haskell by declaring what something is instead of declaring how you get it. That's why there are no while loops or for loops in Haskell and instead we many times have to use recursion to declare what something is.
The principle of tail recursion is to perform all computation first before the recursive call, often giving the results of the computation as additional argument to the recursively called function. Thus in tail recursion the recursive call is the last logic instruction in the recursive function.
In Haskell, lists are a homogenous data structure. It stores several elements of the same type. That means that we can have a list of integers or a list of characters but we can't have a list that has a few integers and then a few characters. And now, a list!
I like your attempt
ls = 0 : f 0 : f (last ls)
These are the problems with it:
f
directly to a list, but it's supposed to operate on list elements. (That's the cause of your error message.)last
on an infinite list can be no good. Anyways this is not what you want: f
should be applied to all elements of the tail instead. That's what map
is there for.So, a correct and complete implementation of that attempt is the following:
iterate' :: (a -> a) -> a -> [a]
-- altn.: (Int->Int) -> [Int], without x₀ but always starting from 0
iterate' f x₀ = ls
where ls = x₀ : f x₀ : map f (tail ls)
N.B. this doesn't actually give [f 0, f (f 0), f (f (f 0)) ..]
but starts from 0
. To start from f 0
, simply remove the standalone x₀
:
iterate' f x₀ = ls
where ls = f x₀ : map f (tail ls)
...which doesn't terminate however (thanks @WillNess), because the tail
would now recurse forever. But you don't actually need tail
! This is the proper definition:
iterate' f x₀ = ls
where ls = f x₀ : map f ls
If you want to define this yourself, vs use iterate as pointed out by @WillemVanOnsem, then simple primitive recursion is your friend:
f :: (a -> a) -> a -> [a]
f g x = let new = g x in new `seq` new : f g new
This is similar to iterate except that iterate starts with the element you provide (the first x
) instead of the first application of the function:
iterate :: (a -> a) -> a -> [a]
iterate f x = x : iterate f (f x)
A self-education can be acquired by hoogling for functions of this type and reading the implementation of any search hits found in the base package.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With