Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a list of recursive calls to a function in Haskell

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?

like image 633
BryceTheGrand Avatar asked Jul 24 '19 14:07

BryceTheGrand


People also ask

How does Haskell recursion work?

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.

Does Haskell support recursion?

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.

What is tail recursion in Haskell?

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.

What does list do in Haskell?

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!


2 Answers

I like your attempt

ls = 0 : f 0 : f (last ls)

These are the problems with it:

  • No type signature. Always write type signatures. They are technically speaking optional, but boy do they help to understand what's going on and what you even want.
  • You're trying to apply 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
like image 60
leftaroundabout Avatar answered Oct 06 '22 03:10

leftaroundabout


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.

like image 28
Thomas M. DuBuisson Avatar answered Oct 06 '22 02:10

Thomas M. DuBuisson