<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/repeatedly-applying-a-function/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://tjmahr.github.io/repeatedly-calling-a-function/"> Higher Order Functions</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>A colleague of mine sent me the following R question:</p>
<blockquote>
<p>I have a function that takes a list and does some stuff to it and then returns<br>
it. I then take that output and run it through the same function again. But I<br>
obviously don’t want to repeatedly type the function out, because I want the<br>
number of function replications to be a declared argument. I had little luck<br>
with <a target="_blank" rel="nofollow" href="http://adv-r.had.co.nz/Functionals.html">functionals</a>, although they<br>
seemed like an obvious choice.</p>
</blockquote>
<p>It goes on to say that the solution should work in a magrittr pipeline, so that<br>
will influence how we solve the problem. Namely, we want to write a<br>
function that will transform a pipeline like:</p>
<div>
<pre><code><span>x</span><span> </span><span>%>%</span><span> </span><span>some_function</span><span>(</span><span>args</span><span>)</span><span> </span><span>%>%</span><span> </span><span>some_function</span><span>(</span><span>args</span><span>)</span><span> </span><span>%>%</span><span> </span><span>some_function</span><span>(</span><span>args</span><span>)</span><span> </span><span>%>%</span><span> </span><span>some_function</span><span>(</span><span>args</span><span>)</span><span>
</span></code></pre>
</div>
<p>into a one-liner like</p>
<div>
<pre><code><span>x</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>.reps</span><span> </span><span>=</span><span> </span><span>4</span><span>,</span><span> </span><span>some_function</span><span>,</span><span> </span><span>args</span><span>)</span><span>
</span></code></pre>
</div>
<h2>Winding up a while loop</h2>
<p>The solution is repeated function application with some book-keeping. We could<br>
do this with a while-loop or even with recursion. Here’s the loop version.</p>
<div>
<pre><code><span>repeated</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>.x</span><span>,</span><span> </span><span>.reps</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>.f</span><span>,</span><span> </span><span>...</span><span>)</span><span> </span><span>{</span><span>
</span><span># A single, finite, non-negative number of repetitions
</span><span> </span><span>assertthat</span><span>::</span><span>assert_that</span><span>(</span><span>
</span><span>length</span><span>(</span><span>.reps</span><span>)</span><span> </span><span>==</span><span> </span><span>1</span><span>,</span><span>
</span><span>!</span><span>is.na</span><span>(</span><span>.reps</span><span>),</span><span>
</span><span>.reps</span><span> </span><span>>=</span><span> </span><span>0</span><span>,</span><span>
</span><span>is.finite</span><span>(</span><span>.reps</span><span>))</span><span>
</span><span># accept purrr-style formula functions
</span><span> </span><span>.f</span><span> </span><span>&lt;-</span><span> </span><span>purrr</span><span>::</span><span>as_function</span><span>(</span><span>.f</span><span>,</span><span> </span><span>...</span><span>)</span><span>
</span><span># 0 .reps
</span><span> </span><span>value</span><span> </span><span>&lt;-</span><span> </span><span>.x</span><span>
</span><span>while</span><span> </span><span>(</span><span>.reps</span><span> </span><span>>=</span><span> </span><span>1</span><span>)</span><span> </span><span>{</span><span>
</span><span>value</span><span> </span><span>&lt;-</span><span> </span><span>.f</span><span>(</span><span>value</span><span>,</span><span> </span><span>...</span><span>)</span><span>
</span><span>.reps</span><span> </span><span>&lt;-</span><span> </span><span>.reps</span><span> </span><span>-</span><span> </span><span>1</span><span>
</span><span>}</span><span>
</span><span>value</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>We start with some basic input-checking on the number of repetitions.<br>
<code>assert_that()</code> is like <code>stopifnot()</code>, but it spells out failures a little more<br>
verbosely. (To be honest, I don’t like that about half of the function is for<br>
checking the number of repetitions, but that’s how it goes…)</p>
<div>
<pre><code><span>library</span><span>(</span><span>purrr</span><span>)</span><span>
</span><span>add</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>,</span><span> </span><span>y</span><span>)</span><span> </span><span>x</span><span> </span><span>+</span><span> </span><span>y</span><span>
</span><span>10</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>-1</span><span>,</span><span> </span><span>add</span><span>,</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> Error: .reps not greater than or equal to 0
</span><span>10</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>1</span><span>:</span><span>10</span><span>,</span><span> </span><span>add</span><span>,</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> Error: length(.reps) not equal to 1
</span></code></pre>
</div>
<p>The next line uses purrr’s <code>as_function()</code>, so that we can also use<br>
formula-based anonymous functions. Here are examples with named functions,<br>
typical anonymous functions and formula-based anonymous functions.</p>
<div>
<pre><code><span># Regular named function
</span><span>1</span><span>:</span><span>4</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>1</span><span>,</span><span> </span><span>add</span><span>,</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> [1] 3 4 5 6
</span><span>1</span><span>:</span><span>4</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>5</span><span>,</span><span> </span><span>add</span><span>,</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> [1] 11 12 13 14
</span><span>
</span><span># Conventional anonymous function
</span><span>1</span><span>:</span><span>4</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>2</span><span>,</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>x</span><span> </span><span>*</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> [1] 4 8 12 16
</span><span>
</span><span># Formula-based anonymous function
</span><span>1</span><span>:</span><span>4</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>4</span><span>,</span><span> </span><span>~</span><span> </span><span>.x</span><span> </span><span>*</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> [1] 16 32 48 64
</span><span>
</span><span># A weird kind of power tower!
</span><span>1</span><span>:</span><span>4</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>4</span><span>,</span><span> </span><span>~</span><span> </span><span>.x</span><span> </span><span>^</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> [1] 1 65536 43046721 4294967296
</span><span>((((</span><span>1</span><span>:</span><span>4</span><span>)</span><span> </span><span>^</span><span> </span><span>2</span><span>)</span><span> </span><span>^</span><span> </span><span>2</span><span>)</span><span> </span><span>^</span><span> </span><span>2</span><span>)</span><span> </span><span>^</span><span> </span><span>2</span><span>
</span><span>#> [1] 1 65536 43046721 4294967296
</span></code></pre>
</div>
<p>Because we are working in a pipeline, we expect the first argument to be some<br>
data. If we apply a function 0 times to the data, it should return the data.<br>
That’s why we set the <code>value</code> to the input before the loop.</p>
<div>
<pre><code><span># 0 function-applications
</span><span>1</span><span>:</span><span>4</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>0</span><span>,</span><span> </span><span>add</span><span>,</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> [1] 1 2 3 4
</span></code></pre>
</div>
<p>This function is built around a while-loop that ticks down every time the<br>
function is applied. Generally, loops are not considered idiomatic R. I<br>
certainly try to avoid writing loops in R because the language has built-in<br>
functions that can abstract over a lot of iteration and the required<br>
book-keeping. If we are iterating over a dimension of something, like<br>
elements in a vector or columns in a data-frame, we can probably write a<br>
loop-free version. But here we are not looping over structure—we are looping<br>
through time! This is fundamentally different kind of problem than the kinds<br>
are that solved by <code>Map()</code> or <code>lapply()</code>. That’s why we had to invent our own<br>
higher-order function to handle this kind of iteration for us.</p>
<h2>Drilling down with recursion</h2>
<p><img alt="Google search for &quot;recursion&quot; says &quot;Did you mean recursion?&quot;" src="https://i2.wp.com/tjmahr.github.io/assets/images/recursion.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>But we can make it loop-free, by torturing the code into recursion. Okay, it’s<br>
not <em>that</em> bad. Here I break it up into an input-handling step which sets the<br>
stage for the recursive function <code>recursively_repeat()</code>.</p>
<div>
<pre><code><span>rrrepeated</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>.x</span><span>,</span><span> </span><span>.reps</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>.f</span><span>,</span><span> </span><span>...</span><span>)</span><span> </span><span>{</span><span>
</span><span># A single, finite, non-negative number of repetitions
</span><span> </span><span>assertthat</span><span>::</span><span>assert_that</span><span>(</span><span>
</span><span>length</span><span>(</span><span>.reps</span><span>)</span><span> </span><span>==</span><span> </span><span>1</span><span>,</span><span>
</span><span>!</span><span>is.na</span><span>(</span><span>.reps</span><span>),</span><span>
</span><span>.reps</span><span> </span><span>>=</span><span> </span><span>0</span><span>,</span><span>
</span><span>is.finite</span><span>(</span><span>.reps</span><span>))</span><span>
</span><span># accept purrr-style formula functions
</span><span> </span><span>.f</span><span> </span><span>&lt;-</span><span> </span><span>purrr</span><span>::</span><span>as_function</span><span>(</span><span>.f</span><span>,</span><span> </span><span>...</span><span>)</span><span>
</span><span>recursively_repeat</span><span>(</span><span>.x</span><span>,</span><span> </span><span>.reps</span><span>,</span><span> </span><span>.f</span><span>,</span><span> </span><span>...</span><span>)</span><span>
</span><span>}</span><span>
</span><span>recursively_repeat</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>.x</span><span>,</span><span> </span><span>.reps</span><span>,</span><span> </span><span>.f</span><span>,</span><span> </span><span>...</span><span>)</span><span> </span><span>{</span><span>
</span><span>if</span><span> </span><span>(</span><span>.reps</span><span> </span><span>==</span><span> </span><span>0</span><span>)</span><span> </span><span>{</span><span>
</span><span>.x</span><span>
</span><span>}</span><span> </span><span>else</span><span> </span><span>{</span><span> </span><span>recursively_repeat</span><span>(</span><span>.f</span><span>(</span><span>.x</span><span>,</span><span> </span><span>...</span><span>),</span><span> </span><span>.reps</span><span> </span><span>-</span><span> </span><span>1</span><span>,</span><span> </span><span>.f</span><span>,</span><span> </span><span>...</span><span>)</span><span>
</span><span># (It would be more correct to use `Recall()` so that renaming the function
</span><span> </span><span># doesn't break this line... -- how's that for an R deep cut?)
</span><span> </span><span>}</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>This is classic recursion. There are two branches. In the <em>base case</em>, when<br>
there are zero repetitions, the work is done and we return the input In the<br>
<em>recursive case</em>, we re-apply the function, take away one of the repetitions<br>
and then try the recursion again—and again and again until we bottom out<br>
and hit the base case.</p>
<p>This verion works like its buddy:</p>
<div>
<pre><code><span>1</span><span>:</span><span>4</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>5</span><span>,</span><span> </span><span>~</span><span> </span><span>.x</span><span> </span><span>-</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> [1] -9 -8 -7 -6
</span><span>1</span><span>:</span><span>4</span><span> </span><span>%>%</span><span> </span><span>rrrepeated</span><span>(</span><span>5</span><span>,</span><span> </span><span>~</span><span> </span><span>.x</span><span> </span><span>-</span><span> </span><span>2</span><span>)</span><span>
</span><span>#> [1] -9 -8 -7 -6
</span><span>
</span><span>echo</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>paste0</span><span>(</span><span>x</span><span>,</span><span> </span><span>&quot; (&quot;</span><span>,</span><span> </span><span>x</span><span>,</span><span> </span><span>&quot;)&quot;</span><span>)</span><span> </span><span>&quot;hello&quot;</span><span> </span><span>%>%</span><span> </span><span>repeated</span><span>(</span><span>2</span><span>,</span><span> </span><span>echo</span><span>)</span><span>
</span><span>#> [1] &quot;hello (hello) (hello (hello))&quot;
</span><span>&quot;hello&quot;</span><span> </span><span>%>%</span><span> </span><span>rrrepeated</span><span>(</span><span>2</span><span>,</span><span> </span><span>echo</span><span>)</span><span>
</span><span>#> [1] &quot;hello (hello) (hello (hello))&quot;
</span></code></pre>
</div>
<p>The main drawback to the recursive version is its readability. I just find it<br>
harder to take in compared to the loop version—at least for a problem this<br>
simple. For more interesting data structures, the recursive version may prove<br>
more elegant and comprehensible.</p>
<p>A minor drawback to the recursive approach is its performance. It’s a little<br>
slower at the median level than the loop approach.</p>
<div>
<pre><code><span>shuffle</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>sample</span><span>(</span><span>x</span><span>)</span><span>
</span><span>microbenchmark</span><span>::</span><span>microbenchmark</span><span>(</span><span>
</span><span>with_while</span><span> </span><span>=</span><span> </span><span>repeated</span><span>(</span><span>1</span><span>:</span><span>100</span><span>,</span><span> </span><span>100</span><span>,</span><span> </span><span>shuffle</span><span>),</span><span>
</span><span>with_recur</span><span> </span><span>=</span><span> </span><span>rrrepeated</span><span>(</span><span>1</span><span>:</span><span>100</span><span>,</span><span> </span><span>100</span><span>,</span><span> </span><span>shuffle</span><span>),</span><span>
</span><span>times</span><span> </span><span>=</span><span> </span><span>1000</span><span>
</span><span>)</span><span>
</span><span>#> Unit: microseconds
#> expr min lq mean median uq max neval
#> with_while 699.331 875.6795 1515.112 1093.551 1589.706 48083.54 1000
#> with_recur 805.234 1037.1000 1796.680 1342.445 2011.684 13889.58 1000
#> cld
#> a #> b
</span></code></pre>
</div>
<p>But I don’t usually worry about performance unless I can notice the computation<br>
taking time.</p>
<p>What I will always notice is R trying to protect me from infinite<br>
recursion when I crank up the number of repetition:</p>
<div>
<pre><code><span>repeated</span><span>(</span><span>1</span><span>:</span><span>20</span><span>,</span><span> </span><span>1000</span><span>,</span><span> </span><span>shuffle</span><span>)</span><span>
</span><span>#> [1] 12 14 2 17 7 19 4 10 13 1 20 9 15 11 6 16 5 18 8 3
</span><span>rrrepeated</span><span>(</span><span>1</span><span>:</span><span>20</span><span>,</span><span> </span><span>1000</span><span>,</span><span> </span><span>shuffle</span><span>)</span><span>
</span><span>#> Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
</span></code></pre>
</div>
<hr>
<p>To recap, we had a problem that centered around a specific kind of iteration:<br>
repeatedly applying function on an input. To solve the problem, I wrote a<br>
higher-order function to handle this kind of iteration. My first pass at the<br>
problem used a simple while loop that ticked down a counter every time the<br>
function was called. Dared by the loop-free purism, I also wrote a recursive<br>
version, but for a problem this simple, it’s more of a curiousity.</p>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://tjmahr.github.io/repeatedly-calling-a-function/"> Higher Order Functions</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/HZ8CbJyRjSo"></a></div>