47

Is there a library function available in Haskell to compose a function with itself n times?

For example I have this function:

func :: a -> a

and I want to do this:

func . func . func . func . func . func , ... 

(up to n times, where n is only known at runtime).

Note that the iterate function would not be appropriate for what I am doing, since I do not care about any intermediate results.

kes
  • 5,983
  • 8
  • 41
  • 69

10 Answers10

63

The iterate solution is fine, or you might like this one: the composition of n copies of f is foldr (.) id (replicate n f).

Reid Barton
  • 14,951
  • 3
  • 39
  • 49
  • 6
    @John The other solutions (`iterate` with `!!` or `lookup . zip`) also work with n == 0. Look at the [definition of iterate](http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/src/GHC-List.html#iterate) and you'll see it starts the list with the base case. – Thomas M. DuBuisson Oct 12 '10 at 14:19
  • @TomMD you're right, my mistake. I was thinking of a different definition using `iterate`, which isn't nearly as nice as what you provided. – John L Oct 12 '10 at 17:08
  • When I use this with `map` as `f` in GHCI, I get an infinite type error. – CMCDragonkai Sep 12 '15 at 08:42
  • It appears to be a problem involving return type polymorphic recursion. – CMCDragonkai Sep 12 '15 at 09:28
29
\xs n -> iterate func xs !! n

(xs is the initial value, n is the number of times to apply func)

I don't know why, but I feel like iterate is something people aren't consistently exposed to when learning Haskell.

If you don't like !! then you could use zip and lookup as an alternative. (some people/groups/tools don't like functions that call "error" in certain cases, I'm not claiming lookup is any better in these cases)

lookup n . zip [0..] . iterate func

EDIT: Ok, so I deleted then undeleted because I agree with the other answerer - you shouldn't discount use of iterate just because it gives you more than you need.

Janus Troelsen
  • 20,267
  • 14
  • 135
  • 196
Thomas M. DuBuisson
  • 64,245
  • 7
  • 109
  • 166
  • 2
    For what it's worth, since `iterate` guarantees an infinite list, I would use `(!!)` or `genericIndex` over using `lookup` with `zip`. – Thomas Eding Oct 12 '10 at 03:40
  • Yes, that's what I was getting out about `lookup` and `zip` not being any better in these cases. `(!!)` has a stigma much like `head` does (or, that's my impression) – Thomas M. DuBuisson Oct 12 '10 at 04:15
  • 9
    Yes, it's a well-deserved stigma in my opinion too, but all it really means is that you have to be careful about using it in cases where it might not apply - not that you should never use it. As trinithis points out, in this case it cannot go wrong except when passed a negative index. Incidentally !! is actually a demonstrably better choice than lookup here: lookup and zip will loop forever on a negative index, looking for a result that isn't there, but !! will fail immediately because it knows indices can't be negative. – mokus Oct 12 '10 at 14:31
14

I do not know why you say that iterate is not appropriate. It is perfectly suitable for this purpose. (!! n) . iterate func is the composition of n copies of func.

(Someone had posted an answer similar to the above code, but he/she seems to have deleted it.)

Tsuyoshi Ito
  • 1,288
  • 11
  • 14
12

(\n -> appEndo . mconcat . replicate n . Endo) n f x

Thomas Eding
  • 35,312
  • 13
  • 75
  • 106
8

I'm a beginner in Haskell, currently on chapter 5 ("Higher Order Functions") of Learn You a Haskell For Great Good! so I'm not yet familiar with the functions shown in the previous replies. Given what I understand so far, I'd do it like this:

applyNTimes :: Int -> (a -> a) -> a -> a
applyNTimes n f x 
    | n == 0        = x
    | otherwise     = f (applyNTimes (n-1) f x)
Tyler
  • 21,762
  • 11
  • 61
  • 90
Aky
  • 1,777
  • 1
  • 14
  • 19
  • 4
    The only thing I would do differently is pattern matching instead of using guards: `applyNTimes 0 _ x = x` and then `applyNTimes n f x = f $ applyNTimes (n-1) f x`. Actually, you should be able to remove all the x's from that as well. – Tyler Sep 15 '11 at 05:26
  • This is also a good solution, it should remind the reader of an explicit proof by induction on [n]. – Artyom Shalkhakov Sep 15 '11 at 05:26
  • 7
    Notice that this is strictly better than `| otherwise = applyNTimes (n-1) f (f x)`, because `f` might be lazy. – Ben Millwood Sep 15 '11 at 16:40
5

Here's a version that has complexity O(log n) instead of O(n) (to build the function, not to apply it):

composeN 0 f = id
composeN n f
    | even n = g
    | odd  n = f . g
    where g = g' . g'
          g' = composeN (n `div` 2) f
Challenger5
  • 959
  • 6
  • 26
  • How has this got so few votes. Is there something wrong with it? – matt Jul 27 '21 at 00:06
  • 2
    @matt Probably because I was late to the party, and because the time complexity of building the function isn't really relevant when you still need O(N) time to execute it anyway. – Challenger5 Jul 27 '21 at 21:18
5
\n -> appEndo . foldMap Endo . replicate n
klapaucius
  • 1,094
  • 8
  • 6
2

A variation on trinithis' answer using the newtype package, just for fun:

(\n f -> under Endo (mconcat . replicate n) f)

Or point-free:

under Endo . (mconcat .) . replicate
Community
  • 1
  • 1
ShinNoNoir
  • 2,274
  • 1
  • 18
  • 24
1

Another solution using foldr:

\n -> flip (foldr ($)) . replicate n

Zark Bardoo
  • 468
  • 5
  • 15
0
iterate (f .) id !! n

or

iterate (f .) f !! (n-1)

depending on if n == 0 is allowed.

Alexey
  • 9,197
  • 5
  • 64
  • 76