Function that applies a function x times on an argument

Viewed 79

Write a doItX :: (a -> a -> a) -> a -> Int -> a function that applies the first parameter f x times on the second parameter.

doItX (*) 2 1 == 2

doItX (++) "a" 6 == "aaaaaa"

doItX (*) 2 3 == 8

I have the following code:

doItX f a x
  | x==1 = a
  | x>1 = doItX f (f a a) (x-1)

That works fine if x is 2 or less, but for the third example, it returns 16 instead of 8.

2 Answers

Probably the most ā€œidiomaticā€ solution would be a library-based one:

doItX1 :: (a -> a -> a) -> a -> Int -> a
doItX1 f a x = foldr1 f (replicate x a)

with Prelude function foldr1 documented here.

But if for some reason of yours, you insist on using manual recursion, your code was almost there. You just need to fix the recursive call:

doItX :: (a -> a -> a) -> a -> Int -> a
doItX f a x
  | (x > 1)    =  ----Was: doItX f (f a a) (x-1)
                  f a (doItX f a (x-1))
  | (x == 1)   =  a
  | otherwise  =  error ("doItX called with x set to " ++ (show x))

Let's consider doItX (*) 2 3.

doItX (*) 2 3
-- doItX f a x
-- f = (*)
-- a = 2
-- x = 3
-- doItX f (f a a) (x-1)
doItX (*) ((*) 2 2) 2
doItX (*) 4 2
doItX (*) ((*) 4 4) 1  -- ups, you wanted `2 * 4` but got `4 * 4`.
                       -- You probably should always pass 2 for a.
16
Related