Home > Back-end >  Need help understanding Haskell id function
Need help understanding Haskell id function

Time:12-07

Hello I have two versions of this function and I am having some trouble.

iter :: Int -> (a -> a) -> (a -> a)
iter n f
  | n > 0 = f . iter (n-1) f
  | otherwise = id

iter' :: Int -> (a -> a) -> (a -> a)
iter' n = foldr (.) id . replicate n

I cannot understand even after googling what does id actually do here.

Like for example if we come to the function with n = 3 and f x = x 1. When we iterate through the whole n and come to the point when id is being called what happens with our variables?

I am very big newbie so could you please explain as simplistically as possible.

CodePudding user response:

Summing a list xs = [x1,x2,...,xn] can be visualized as

x1   x2   ...   xn   0

Note that 0 at the very end. Its purpose is to handle the case where the list is empty, i.e. xs = [] and n=0. In such case the sum above reduces to 0, which is the correct sum for an empty list.

Also note that when the list is not empty the extra 0 has no impact ont the sum, so it's harmless. We indeed choose 0 since it is the neutral element for addition: x 0 = x for all x.

If we want to compute a product, we would write

x1 * x2 * ... * xn * 1

Note that * 1 at the end. Its role is exactly the same as the 0 seen above. Also note that 1 is the neutral element of multiplication: x * 1 = x for all x.

If we want to compute the composition of a list of functions, we would write

f1 . f2 . ... . fn . id

Note that . id at the end. Its role is exactly the same as the 0 and * 1 seen above. Also note that id is the neutral element of composition f . id = f for all f.

Hopefully this will help you understand why, every time we compute a fold like

x1 op x2 op ... op xn

where op is any binary operation, we want to end with ... op neutral_element so to handle the empty list case, and still act as a good base case for non-empty lists.

CodePudding user response:

You can inline:

iter 3 f
f . iter 2 f
f . (f . iter 1 f)
f . (f . (f . iter 0 f)
f . (f . (f . id))

-- adding the argument x
iter 3 f x
(f . (f . (f . id))) x
-- using (g . h) x == g (h x)
f ((f . (f . id)) x)
f (f ((f . id) x))
f (f (f (id x)))
f (f (f x))

And in the case of iter':

iter' 3 f
(foldr (.) id . replicate 3) f
foldr (.) id (replicate 3 f)
foldr (.) id [f, f, f]
(.) f (foldr (.) id [f, f]]
(.) f ((.) f (foldr (.) id [f]))
(.) f ((.) f ((.) f (foldr (.) id [])))
(.) f ((.) f ((.) f id))
f . (f . (f . id))
  • Related