<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/iteration-and-closures-in-r/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.win-vector.com/blog/2017/02/iteration-and-closures-in-r/"> R – Win-Vector Blog</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>I recently read an <a target="_blank" rel="nofollow" href="https://twitter.com/vsbuffalo/status/834890656157843457">interesting thread</a> on unexpected behavior in <code>R</code> when creating a list of functions in a loop or iteration. The issue is solved, but I am going to take the liberty to try and re-state and slow down the discussion of the problem (and fix) for clarity.</p>
<p>The issue is: are references or values captured during iteration?</p>
<p>Many users expect values to be captured. Most programming language implementations capture variables or references (leading to strange aliasing issues). It is confusing (especially in R, which pushes so far in the direction of value oriented semantics) and best demonstrated with concrete examples.</p>
<p><center><br>
<img title="NewImage.png" alt="NewImage" src="https://i1.wp.com/www.win-vector.com/blog/wp-content/uploads/2017/02/NewImage-7.png?resize=143%2C125" border="0" data-recalc-dims="1"><br>
</center></p>
<p>Please read on for a some of the history and future of this issue.<span></span></p>
<p>
<h3><code>for</code> loops</h3>
<p>Consider the following code run in <code>R version 3.3.2 (2016-10-31)</code>:</p>
<pre>
 functionsFor &lt;- vector(2, mode='list')
 for(x in 1:2) { 
   functionsFor[[x]] &lt;- function() return(x)
 }

 functionsFor[[1]]()

 # [1] 2
</pre>
<p>In real applications the functions would take additional arguments and perform calculations involving both the “partially applied” <code>x</code> and these future arguments. Obviously if we just wanted values we would not use functions. However, this trivial example is much simpler (except for the feeling it is silly) than a substantial application. The notation gets confusing even as we stand. But partial application (binding values into functions) is a common functional programming pattern (which happens to not always interact well with iteration).</p>
<p>Notice the answer printed is 2 (not 1).</p>
<p>This is because all the functions created in the loop captured a closure or reference to the same variable <code>x</code> (which is 2 at the end of the loop). The functions did not capture the value <code>x</code> had when the functions were created. We can confirm this by moving <code>x</code> around by hand, as we show below.</p>
<pre>
 x &lt;- 4
 functionsFor[[1]]()

 # [1] 4
</pre>
<p>This is a well know language design issue. </p>
<ul>
<li><a target="_blank" rel="nofollow" href="https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the-loop-variable-considered-harmful/">C# had this issue</a> (and is fairly unique in having eventually fixed it!).</li>
<li><a target="_blank" rel="nofollow" href="https://lorgonblog.wordpress.com/2008/11/12/on-lambdas-capture-and-mutability/">F# has the issue</a>.</li>
<li><a target="_blank" rel="nofollow" href="https://github.com/golang/go/wiki/CommonMistakes">Go has the issue</a>.</li>
</ul>
<h3>Trying to work-around it</h3>
<p>The more complicated examples referenced in the thread are variations of the standard work-around: build a function factory so each function has a different closure (the new closures being the execution environments of each factory invocation). That code looks like the following:</p>
<pre>
 functionsFor2 &lt;- vector(2, mode='list')
 for(x in 1:2) {
   functionsFor2[[x]] &lt;- (function(x) {
     return(function() return(x))
   })(x)
 }

 functionsFor2[[1]]()

 # [1] 2</pre>
<p>The outer function (which gets called) is called the factory and is trivial (we are only using it to get new environments). The inner function is our example, which in the real world would take additional arguments and perform calculations involving these arguemnts in addition to <code>x</code>.</p>
<p>Notice the “fix” did not work. There is more than one problem lurking, and this is why so many experienced functional programmers are surprised by the behavior (despite probably having experience in many of the other functional languages we have mentioned). <code>R</code> “functions” are different than many current languages in that they have semantics closer to what <code>Lisp</code> called an <a target="_blank" rel="nofollow" href="https://en.wikipedia.org/wiki/Fexpr"><code>fexpr</code></a>. In particular arguments are subject to “<a target="_blank" rel="nofollow" href="https://en.wikipedia.org/wiki/Lazy_evaluation">lazy evaluation</a>” (a feature <code>R</code> implements by a bookeeping process called “<a target="_blank" rel="nofollow" href="https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Promise-objects">promises</a>“).</p>
<p>So in addition to the (probably expected) unwanted shared closure issue, we have a lazy evaluation issue. The complete fix involves both introducing new closures (by the using the function factory’s execution closure) and forcing evaluation in these new environments. We show the code below:</p>
<pre>
 functionsFor3 &lt;- vector(2, mode='list')
 for(x in 1:2) {
   functionsFor3[[x]] &lt;- (function(x) {
     force(x)
     return(function() return(x))
   })(x)
 }

 functionsFor3[[1]]()
 # [1] 1
</pre>
<p>Lazy evaluation is a fairly rare language feature (most famously used in <a target="_blank" rel="nofollow" href="https://en.wikipedia.org/wiki/Haskell_(programming_language)"><code>Haskell</code></a>), so it is not always everybody’s mind. <code>R</code> has lazy evaluation a number of places (function arguments and <code>dplyr</code> pipelines and data-structures being some of the most prominent uses).</p>
<h3><code>lapply</code> and <code>purrr::map</code></h3>
<p>I’ve taught this issue for years in our advanced <code>R</code>-programming workshops.</p>
<p>One thing I didn’t know is: <code>R</code> fixed this issue for <code>base::lapply()</code>. Consider the following code:</p>
<pre>
 functionsL &lt;- lapply(1:2, 
   function(x) { function() return(x) })

 functionsL[[1]]()

 # [1] 1
</pre>
<p>Apparently <code>lapply</code> <a target="_blank" rel="nofollow" href="https://stat.ethz.ch/pipermail/r-devel/2015-February/070686.html">used to have the problem</a> and was fixed by the time we got to <code>R 3.2</code>. </p>
<p>Coming back to the original thread, the current <code>CRAN</code> release of <code>purrr</code> (<code>0.2.2</code>) also has the reference behavior, as we can see below:</p>
<pre>
 functionsM &lt;- purrr::map(1:2, 
   function(x) { function() return(x) })

 functionsM[[1]]()

 # [1] 2
</pre>
<p>Apparently this is <a target="_blank" rel="nofollow" href="https://github.com/hadley/purrr/issues/191">scheduled for a fix</a>.</p>
<p>Though, there is no way <code>purrr::map()</code> can behave the same as both <code>for(){}</code> and <code>lapply()</code> as the two currently have different behavior.</p>
<h3>Conclusion</h3>
<p>Lazy evaluation can increase complexity as it makes it less obvious to the programmer when something will be executed and increases the number of possible interactions the programmer can experience (as it is not determined when code will run, so one can not always know the state of the world it will run in).</p>
<p>My opinion is: lazy evaluation should be used sparingly in <code>R</code>, and only where it is trading non-determinism for some benefit. I would also point out that lazy evaluation is not the only possible way to capture specifications of calculations for future interpretation even in <code>R</code>. For example, formula-like interfaces also provide this capability.</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="http://www.win-vector.com/blog/2017/02/iteration-and-closures-in-r/"> R – Win-Vector Blog</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/ckJXSIGlTBQ"></a></div>