<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/using-nonstandard-evaluation-to-simulate-a-register-machine/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://tjmahr.github.io/nonstandard-eval-register-machines/"> Higher Order Functions</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>I recently completed all 25 days of <a rel="nofollow" href="http://adventofcode.com/2017" title="Advent of Code 2017" target="_blank">Advent of Code 2017</a>, an annual<br>
series of recreational programming puzzles. Each day describes a programming<br>
puzzle and illustrates a handful of simple examples of the problem. The puzzle<br>
then requires the participant to solve a much, much larger form of the problem.</p>
<p>For five or so of the puzzles, I used <em>nonstandard evaluation</em> to implement my<br>
solution. <a rel="nofollow" href="https://tjmahr.github.io/set-na-where-nonstandard-evaluation-use-case/" title="set_na_where(): a nonstandard evaluation use case" target="_blank">As I previously wrote</a>, nonstandard evaluation is a way of<br>
bottling up magic spells (lines of R code) and changing how or where they are<br>
cast (evaluated). I chose to use special evaluation not because it was the<br>
easiest or most obvious solution but because I wanted to develop my skills with<br>
computing on the language. In this post, I work through one of the examples<br>
where I used nonstandard evaluation to write an interpreter for a simple<br>
machine.</p>
<h2>Puzzle description</h2>
<p><a rel="nofollow" href="http://adventofcode.com/2017/day/8" target="_blank">Day 8</a> requires us to simulate the state<br>
of a register machine as it receives a series of instructions.</p>
<blockquote>
<p>Each instruction consists of several parts: the register to modify, whether to<br>
increase or decrease that register’s value, the amount by which to increase or<br>
decrease it, and a condition. If the condition fails, skip the instruction<br>
without modifying the register. The registers all start at <code>0</code>. The instructions<br>
look like this:</p>
<div>
<div>
<pre><code>b inc 5 if a > 1
a inc 1 if b &lt; 5
c dec -10 if a >= 1
c inc -20 if c == 10
</code></pre>
</div></div>
<p>[…]</p>
<p>You might also encounter <code>&lt;=</code> (less than or equal to) or <code>!=</code> (not equal to).<br>
However, the CPU doesn’t have the bandwidth to tell you what all the registers<br>
are named, and leaves that to you to determine.</p>
<p><strong>What is the largest value in any register</strong> after completing the<br>
instructions in your puzzle input?</p>
</blockquote>
<p>If I squint long enough at the register instructions, I can basically<br>
see R code.</p>
<div>
<div>
<pre><code><span># b inc 5 if a > 1</span><span>
</span><span>b</span><span> </span><span>&lt;-</span><span> </span><span>if</span><span> </span><span>(</span><span>a</span><span> </span><span>></span><span> </span><span>1</span><span>)</span><span> </span><span>b</span><span> </span><span>+</span><span> </span><span>5</span><span> </span><span>else</span><span> </span><span>b</span><span>
</span><span># a inc 1 if b &lt; 5</span><span>
</span><span>a</span><span> </span><span>&lt;-</span><span> </span><span>if</span><span> </span><span>(</span><span>b</span><span> </span><span></span><span> </span><span>5</span><span>)</span><span> </span><span>a</span><span> </span><span>+</span><span> </span><span>1</span><span> </span><span>else</span><span> </span><span>a</span><span>
</span><span># c dec -10 if a >= 1</span><span>
</span><span>c</span><span> </span><span>&lt;-</span><span> </span><span>if</span><span> </span><span>(</span><span>a</span><span> </span><span>>=</span><span> </span><span>1</span><span>)</span><span> </span><span>c</span><span> </span><span>-</span><span> </span><span>-10</span><span> </span><span>else</span><span> </span><span>c</span><span>
</span><span># c inc -20 if c == 10</span><span>
</span><span>c</span><span> </span><span>&lt;-</span><span> </span><span>if</span><span> </span><span>(</span><span>c</span><span> </span><span>==</span><span> </span><span>10</span><span>)</span><span> </span><span>c</span><span> </span><span>+</span><span> </span><span>-20</span><span> </span><span>else</span><span> </span><span>c</span><span>
</span></code></pre>
</div>
</div>
<p>If we can set up a way to convert the machine instructions into R code, R will<br>
handle the job of looking up values, modifying values and evaluating the logic<br>
and <code>if</code> statements. In other words, if we can convert register instructions<br>
into R code, <strong>the problem simplifies into something like running an R script</strong>.</p>
<p>And that’s a good strategy, because we have a lot of instructions to process.<br>
Each user receives some unique (I think) input for each problem, and my problem<br>
input contains 1,000 instructions.</p>
<div>
<div>
<pre><code><span>library</span><span>(</span><span>magrittr</span><span>)</span><span>
</span><span>full_input</span><span> </span><span>&lt;-</span><span> </span><span>&quot;https://raw.githubusercontent.com&quot;</span><span> </span><span>%>%</span><span> </span><span>file.path</span><span>(</span><span>&quot;tjmahr&quot;</span><span>,</span><span> </span><span>&quot;adventofcode17&quot;</span><span>,</span><span> </span><span>&quot;master&quot;</span><span>,</span><span> </span><span>&quot;inst&quot;</span><span>,</span><span> </span><span>&quot;input08.txt&quot;</span><span>)</span><span> </span><span>%>%</span><span> </span><span>readr</span><span>::</span><span>read_lines</span><span>()</span><span>
</span><span>length</span><span>(</span><span>full_input</span><span>)</span><span>
</span><span>#> [1] 1000</span><span>
</span><span>head</span><span>(</span><span>full_input</span><span>)</span><span>
</span><span>#> [1] &quot;kd dec -37 if gm &lt;=9&quot; &quot;x dec -715 if kjn == 0&quot; </span><span>
</span><span>#> [3] &quot;ey inc 249 if x &lt; 722&quot; &quot;n dec 970 if t > 3&quot; </span><span>
</span><span>#> [5] &quot;f dec -385 if msg > -3&quot; &quot;kd dec -456 if ic &lt;=-8&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>Our strategy for simulating the register machine will have the following steps:</p>
<ul>
<li>Parsing a register instruction</li>
<li>Creating an R expression from an instruction</li>
<li>Evaluating an R expression <em>inside</em> of a register machine</li>
<li>Changing the evaluation rules to adapt to the quirks of this problem</li>
</ul>
<h2>Parsing the register instructions with regular expressions</h2>
<p>The instructions have a very simple grammar. Here is how I would tag the first<br>
few lines of my problem input.</p>
<div>
<div>
<pre><code>[target] [verb] [num1] if [s1] [op] [num2]
      kd    dec    -37 if   gm   &lt;=     9
       x    dec   -715 if  kjn   ==     0
      ey    inc    249 if    x    &lt;   722
       n    dec    970 if    t    >     3
       f    dec   -385 if  msg    >    -3
</code></pre>
</div>
</div>
<p>We can parse these lines using regular expressions. Regular expressions are an<br>
incredibly powerful language for processing text using pattern-matching rules. I<br>
will walk through each of the regular expression patterns used to parse an<br>
instruction.</p>
<p>To match the verbs, we can use the <a rel="nofollow" href="https://www.regular-expressions.info/alternation.html" title="Alternation in regular expressions" target="_blank">or <code>|</code> operator</a>, so<br>
<code>(inc|dec)</code> matches <code>inc</code> or <code>dec</code>. We can also match the six different<br>
comparison operators using <code>|</code> too. In the code below, I put the patterns in<br>
parentheses so that they will be treated as a single group.</p>
<div>
<div>
<pre><code><span>re_verb</span><span> </span><span>&lt;-</span><span> </span><span>&quot;(inc|dec)&quot;</span><span>
</span><span>re_op</span><span> </span><span>&lt;-</span><span> </span><span>&quot;(>|&lt;|==|!=|>=|&lt;=)&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>A register name is just a sequence of letters. The special character <code>\w</code><br>
matches any <em>word</em> character; that is, it matches uppercase/lowercase letters,<br>
digits and underscores. <a rel="nofollow" href="https://www.regular-expressions.info/repeat.html" title="Repetition in regular expressions" target="_blank">The <code>(token)+</code> suffix</a> matches 1 or more<br>
repetitions of a token. Putting these two together, <code>\w+</code> will match 1 or<br>
more adjacent word characters. That pattern in principle could matches things<br>
beside register names (like numbers) but the instruction format here is so<br>
constrained that it’s not a problem.</p>
<div>
<div>
<pre><code><span># We have to double the backslashes when using them in R strings</span><span>
</span><span>re_name</span><span> </span><span>&lt;-</span><span> </span><span>&quot;(\\w+)&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>Numbers are just integers, and sometimes they are negative. A number here<br>
is an optional <code>-</code> plus some digits. The special character <code>\d</code> matches any<br>
digit from 0 to 9, so <code>\d+</code> matches 1 or more successive digits. We can use<br>
<a rel="nofollow" href="https://www.regular-expressions.info/optional.html" title="Optional matching in regular expressions" target="_blank">the <code>(token)?</code> suffix</a> to match an optional token. In our case,<br>
<code>-?\d+</code> will match a sequence of digits and match leading hyphen if one is<br>
present.</p>
<div>
<div>
<pre><code><span>re_number</span><span> </span><span>&lt;-</span><span> </span><span>&quot;(-?\\d+)&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>Each pattern in parentheses is a matching group, and the function <code>str_match()</code><br>
from <a rel="nofollow" href="http://stringr.tidyverse.org/" target="_blank">the stringr package</a> will return a matrix<br>
with a column for each matched group. I also include an extra set of<br>
parentheses around the condition in the <code>if</code> statement to also match the whole<br>
condition as well as its parts.</p>
<div>
<div>
<pre><code><span># Combine the sub-patterns together</span><span>
</span><span>re</span><span> </span><span>&lt;-</span><span> </span><span>sprintf</span><span>(</span><span>&quot;%s %s %s if (%s %s %s)&quot;</span><span>,</span><span> </span><span>re_name</span><span>,</span><span> </span><span>re_verb</span><span>,</span><span> </span><span>re_number</span><span>,</span><span> </span><span>re_name</span><span>,</span><span> </span><span>re_op</span><span>,</span><span> </span><span>re_number</span><span>)</span><span>
</span><span>re</span><span>
</span><span>#> [1] &quot;(\\w+) (inc|dec) (-?\\d+) if ((\\w+) (>|&lt;|==|!=|>=|&lt;=) (-?\\d+))&quot;</span><span>
</span><span>text</span><span> </span><span>&lt;-</span><span> </span><span>&quot;b inc 5 if a > 1&quot;</span><span>
</span><span>stringr</span><span>::</span><span>str_match</span><span>(</span><span>text</span><span>,</span><span> </span><span>re</span><span>)</span><span>
</span><span>#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]</span><span>
</span><span>#> [1,] &quot;b inc 5 if a > 1&quot; &quot;b&quot; &quot;inc&quot; &quot;5&quot; &quot;a > 1&quot; &quot;a&quot; &quot;>&quot; &quot;1&quot;</span><span>
</span><span># Column 5 matches the subgroups in columns 6, 7 and 8 as a single </span><span>
</span><span># group because of the extra grouping parentheses after the `if`.</span><span>
</span></code></pre>
</div>
</div>
<p>We can package this step into a function that takes an instruction’s<br>
text and returns a list with the labelled parts of that instruction.</p>
<div>
<div>
<pre><code><span>parse_instruction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>text</span><span>)</span><span> </span><span>{</span><span>
</span><span>stopifnot</span><span>(</span><span>length</span><span>(</span><span>text</span><span>)</span><span> </span><span>==</span><span> </span><span>1</span><span>)</span><span>
</span><span>re</span><span> </span><span>&lt;-</span><span> </span><span>&quot;(\\w+) (inc|dec) (-?\\d+) if ((\\w+) (>|&lt;|==|!=|>=|&lt;=) (-?\\d+))&quot;</span><span>
</span><span>text</span><span> </span><span>%>%</span><span> </span><span>stringr</span><span>::</span><span>str_match</span><span>(</span><span>re</span><span>)</span><span> </span><span>%>%</span><span> </span><span>as.list</span><span>()</span><span> </span><span>%>%</span><span> </span><span>setNames</span><span>(</span><span>c</span><span>(</span><span>&quot;instruction&quot;</span><span>,</span><span> </span><span>&quot;target&quot;</span><span>,</span><span> </span><span>&quot;verb&quot;</span><span>,</span><span> </span><span>&quot;num1&quot;</span><span>,</span><span>
</span><span>&quot;cond&quot;</span><span>,</span><span> </span><span>&quot;s1&quot;</span><span>,</span><span> </span><span>&quot;op&quot;</span><span>,</span><span> </span><span>&quot;num2&quot;</span><span>))</span><span>
</span><span>}</span><span>
</span><span>str</span><span>(</span><span>parse_instruction</span><span>(</span><span>text</span><span>))</span><span>
</span><span>#> List of 8</span><span>
</span><span>#> $ instruction: chr &quot;b inc 5 if a > 1&quot;</span><span>
</span><span>#> $ target : chr &quot;b&quot;</span><span>
</span><span>#> $ verb : chr &quot;inc&quot;</span><span>
</span><span>#> $ num1 : chr &quot;5&quot;</span><span>
</span><span>#> $ cond : chr &quot;a > 1&quot;</span><span>
</span><span>#> $ s1 : chr &quot;a&quot;</span><span>
</span><span>#> $ op : chr &quot;>&quot;</span><span>
</span><span>#> $ num2 : chr &quot;1&quot;</span><span>
</span></code></pre>
</div>
</div>
<h2>Creating R code</h2>
<p>Next, we need to convert some strings into R code. We can do this with<br>
<code>rlang::parse_expr()</code>. It takes a string and creates an R expression,<br>
something I’ve described as a kind of <a rel="nofollow" href="https://tjmahr.github.io/set-na-where-nonstandard-evaluation-use-case/" title="set_na_where(): a nonstandard evaluation use case" target="_blank">bottled up magic spell</a>: An<br>
expression captures magic words (code) allow us to manipulate or cast (evaluate)<br>
them.</p>
<div>
<div>
<pre><code><span>code</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>parse_expr</span><span>(</span><span>&quot;print('hello')&quot;</span><span>)</span><span>
</span><span>code</span><span>
</span><span>#> print(&quot;hello&quot;)</span><span>
</span><span>code</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>parse_expr</span><span>(</span><span>&quot;if (a > 1) b + 5 else b&quot;</span><span>)</span><span>
</span><span>code</span><span>
</span><span>#> if (a > 1) b + 5 else b</span><span>
</span></code></pre>
</div>
</div>
<p>The format of the instructions is relatively straightforward. We can fill<br>
in a template with the parts of the parsed line. Because <code>inc/dec</code> are just<br>
addition and subtraction, we replace them with the appropriate math operations.</p>
<div>
<div>
<pre><code><span>create_r_instruction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>parsed</span><span>)</span><span> </span><span>{</span><span>
</span><span>parsed</span><span>$</span><span>math</span><span> </span><span>&lt;-</span><span> </span><span>if</span><span> </span><span>(</span><span>parsed</span><span>$</span><span>verb</span><span> </span><span>==</span><span> </span><span>&quot;inc&quot;</span><span>)</span><span> </span><span>&quot;+&quot;</span><span> </span><span>else</span><span> </span><span>&quot;-&quot;</span><span>
</span><span>code</span><span> </span><span>&lt;-</span><span> </span><span>sprintf</span><span>(</span><span>&quot;if (%s) %s %s %s else %s&quot;</span><span>,</span><span> </span><span>parsed</span><span>$</span><span>cond</span><span>,</span><span> </span><span>parsed</span><span>$</span><span>target</span><span>,</span><span> </span><span>parsed</span><span>$</span><span>math</span><span>,</span><span> </span><span>parsed</span><span>$</span><span>num1</span><span>,</span><span> </span><span>parsed</span><span>$</span><span>target</span><span>)</span><span>
</span><span>rlang</span><span>::</span><span>parse_expr</span><span>(</span><span>code</span><span>)</span><span>
</span><span>}</span><span>
</span><span>r_code</span><span> </span><span>&lt;-</span><span> </span><span>&quot;b inc 5 if a > 1&quot;</span><span> </span><span>%>%</span><span>
</span><span>parse_instruction</span><span>()</span><span> </span><span>%>%</span><span> </span><span>create_r_instruction</span><span>()</span><span>
</span><span>r_code</span><span>
</span><span>#> if (a > 1) b + 5 else b</span><span>
</span></code></pre>
</div>
</div>
<h2>Create the register machine</h2>
<p>We have to figure out <em>where</em> we want to evaluate the generated R code. We<br>
create a register object to hold the values. The object will just be a <code>list()</code><br>
with some extra metadata. This object will be the location where the R code<br>
is evaluated.</p>
<div>
<div>
<pre><code><span>create_register_machine</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>...</span><span>)</span><span> </span><span>{</span><span>
</span><span>initial</span><span> </span><span>&lt;-</span><span> </span><span>list</span><span>(</span><span>...</span><span>)</span><span>
</span><span>data</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>initial</span><span>,</span><span> </span><span>list</span><span>(</span><span>.metadata</span><span> </span><span>=</span><span> </span><span>list</span><span>()))</span><span>
</span><span>structure</span><span>(</span><span>data</span><span>,</span><span> </span><span>class</span><span> </span><span>=</span><span> </span><span>c</span><span>(</span><span>&quot;register_machine&quot;</span><span>,</span><span> </span><span>&quot;list&quot;</span><span>))</span><span>
</span><span>}</span><span>
</span><span># Give the machines a pretty print method</span><span>
</span><span>print.register_machine</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>,</span><span> </span><span>...</span><span>)</span><span> </span><span>{</span><span>
</span><span>utils</span><span>::</span><span>str</span><span>(</span><span>x</span><span>,</span><span> </span><span>...</span><span>)</span><span>
</span><span>invisible</span><span>(</span><span>x</span><span>)</span><span>
</span><span>}</span><span>
</span><span>create_register_machine</span><span>()</span><span>
</span><span>#> List of 1</span><span>
</span><span>#> $ .metadata: list()</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>For now, we can initialize registers by using named arguments to the function.</p>
<div>
<div>
<pre><code><span>create_register_machine</span><span>(</span><span>a</span><span> </span><span>=</span><span> </span><span>0</span><span>,</span><span> </span><span>b</span><span> </span><span>=</span><span> </span><span>0</span><span>)</span><span>
</span><span>#> List of 3</span><span>
</span><span>#> $ a : num 0</span><span>
</span><span>#> $ b : num 0</span><span>
</span><span>#> $ .metadata: list()</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span></code></pre>
</div>
</div>
<h2>Evaluating code inside of the machine</h2>
<p>So far, we have:</p>
<ul>
<li>A way to analyze register instructions and convert them into R code</li>
<li>An object that holds register values</li>
</ul>
<p>Now, we need to evaluate an expression <em>inside</em> of the register. We will use<br>
<a rel="nofollow" href="http://rlang.tidyverse.org/articles/tidy-evaluation.html" title="Description of tidy evaluation" target="_blank">tidy evaluation</a>; the function <code>eval_tidy()</code> lets us evaluate an<br>
R expression inside of a data object.</p>
<div>
<div>
<pre><code><span>r_code</span><span>
</span><span>#> if (a > 1) b + 5 else b</span><span>
</span><span># b + 5</span><span>
</span><span>r</span><span> </span><span>&lt;-</span><span> </span><span>create_register_machine</span><span>(</span><span>a</span><span> </span><span>=</span><span> </span><span>4</span><span>,</span><span> </span><span>b</span><span> </span><span>=</span><span> </span><span>7</span><span>)</span><span>
</span><span>rlang</span><span>::</span><span>eval_tidy</span><span>(</span><span>r_code</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>r</span><span>)</span><span>
</span><span>#> [1] 12</span><span>
</span><span># just b</span><span>
</span><span>r</span><span> </span><span>&lt;-</span><span> </span><span>create_register_machine</span><span>(</span><span>a</span><span> </span><span>=</span><span> </span><span>0</span><span>,</span><span> </span><span>b</span><span> </span><span>=</span><span> </span><span>7</span><span>)</span><span>
</span><span>rlang</span><span>::</span><span>eval_tidy</span><span>(</span><span>r_code</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>r</span><span>)</span><span>
</span><span>#> [1] 7</span><span>
</span></code></pre>
</div>
</div>
<p>Now, we need to actually do something. We need to update the register machine<br>
using the value from the evaluated instruction. Otherwise, the machine will just<br>
read expressions and forget everything it’s read.</p>
<p>To update the machine, we have to determine the register to update. Fortunately,<br>
our generated code always ends with an <code>else</code> branch that has the target<br>
register.</p>
<div>
<div>
<pre><code><span>r_code</span><span>
</span><span>#> if (a > 1) b + 5 else b</span><span>
</span></code></pre>
</div>
</div>
<p>If we can pull out that symbol after the <code>else</code>, we will have the name of<br>
register to update in the machine. Because the code is so formulaic, we can just<br>
extract the symbol directly using the code’s <a rel="nofollow" href="http://adv-r.had.co.nz/Expressions.html#structure-of-expressions" title="Advanced R chapter on Expressions" target="_blank">abstract syntax tree (AST)</a>.<br>
<code>pryr::call_tree()</code> shows the AST for an expression.</p>
<div>
<div>
<pre><code><span>pryr</span><span>::</span><span>call_tree</span><span>(</span><span>r_code</span><span>)</span><span>
</span><span>#> \- ()</span><span>
</span><span>#> \- `if</span><span>
</span><span>#> \- ()</span><span>
</span><span>#> \- `></span><span>
</span><span>#> \- `a</span><span>
</span><span>#> \- 1</span><span>
</span><span>#> \- ()</span><span>
</span><span>#> \- `+</span><span>
</span><span>#> \- `b</span><span>
</span><span>#> \- 5</span><span>
</span><span>#> \- `b</span><span>
</span></code></pre>
</div>
</div>
<p>We can extract elements from the tree like elements in a list by selecting<br>
indices.</p>
<div>
<div>
<pre><code><span># The numbers match one of the slashs at the first level of indentation</span><span>
</span><span>r_code</span><span>[[</span><span>1</span><span>]]</span><span>
</span><span>#> `if`</span><span>
</span><span>r_code</span><span>[[</span><span>2</span><span>]]</span><span>
</span><span>#> a > 1</span><span>
</span><span># We can crawl down subtrees too</span><span>
</span><span>r_code</span><span>[[</span><span>2</span><span>]][[</span><span>2</span><span>]]</span><span>
</span><span>#> a</span><span>
</span><span># But what we want is the last branch from the `if` level</span><span>
</span><span>r_code</span><span>[[</span><span>4</span><span>]]</span><span>
</span><span>#> b</span><span>
</span></code></pre>
</div>
</div>
<p>If we convert the symbol into a string, we can look it up in the register using<br>
the usual list lookup syntax.</p>
<div>
<div>
<pre><code><span>r</span><span> </span><span>&lt;-</span><span> </span><span>create_register_machine</span><span>(</span><span>a</span><span> </span><span>=</span><span> </span><span>4</span><span>,</span><span> </span><span>b</span><span> </span><span>=</span><span> </span><span>7</span><span>)</span><span>
</span><span>target</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>as_string</span><span>(</span><span>r_code</span><span>[[</span><span>4</span><span>]])</span><span>
</span><span>r</span><span>[[</span><span>target</span><span>]]</span><span>
</span><span>#> [1] 7</span><span>
</span></code></pre>
</div>
</div>
<p>We can also use list lookup syntax with assignment to <em>modify</em> the register.</p>
<div>
<div>
<pre><code><span>r</span><span>[[</span><span>target</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>eval_tidy</span><span>(</span><span>r_code</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>r</span><span>)</span><span>
</span><span>r</span><span>
</span><span>#> List of 3</span><span>
</span><span>#> $ a : num 4</span><span>
</span><span>#> $ b : num 12</span><span>
</span><span>#> $ .metadata: list()</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>Let’s wrap these steps into a function.</p>
<div>
<div>
<pre><code><span>eval_instruction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>register_machine</span><span>,</span><span> </span><span>instruction</span><span>)</span><span> </span><span>{</span><span>
</span><span>target</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>as_string</span><span>(</span><span>instruction</span><span>[[</span><span>4</span><span>]])</span><span>
</span><span>register_machine</span><span>[[</span><span>target</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>eval_tidy</span><span>(</span><span>
</span><span>expr</span><span> </span><span>=</span><span> </span><span>instruction</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>register_machine</span><span>)</span><span>
</span><span>register_machine</span><span>
</span><span>}</span><span>
</span><span>create_register_machine</span><span>(</span><span>a</span><span> </span><span>=</span><span> </span><span>2</span><span>,</span><span> </span><span>b</span><span> </span><span>=</span><span> </span><span>0</span><span>)</span><span> </span><span>%>%</span><span> </span><span>eval_instruction</span><span>(</span><span>r_code</span><span>)</span><span>
</span><span>#> List of 3</span><span>
</span><span>#> $ a : num 2</span><span>
</span><span>#> $ b : num 5</span><span>
</span><span>#> $ .metadata: list()</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span><span>create_register_machine</span><span>(</span><span>a</span><span> </span><span>=</span><span> </span><span>2</span><span>,</span><span> </span><span>b</span><span> </span><span>=</span><span> </span><span>0</span><span>)</span><span> </span><span>%>%</span><span> </span><span># For quick testing, we pass in quoted expressions</span><span>
</span><span>eval_instruction</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>a</span><span> </span><span>></span><span> </span><span>1</span><span>)</span><span> </span><span>b</span><span> </span><span>-</span><span> </span><span>100</span><span> </span><span>else</span><span> </span><span>b</span><span>))</span><span> </span><span>%>%</span><span> </span><span># Should not run</span><span>
</span><span>eval_instruction</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>a</span><span> </span><span></span><span> </span><span>1</span><span>)</span><span> </span><span>b</span><span> </span><span>+</span><span> </span><span>5</span><span> </span><span>else</span><span> </span><span>b</span><span>))</span><span> </span><span>%>%</span><span> </span><span># Should run</span><span>
</span><span>eval_instruction</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>a</span><span> </span><span>></span><span> </span><span>1</span><span>)</span><span> </span><span>a</span><span> </span><span>+</span><span> </span><span>10</span><span> </span><span>else</span><span> </span><span>a</span><span>))</span><span>
</span><span>#> List of 3</span><span>
</span><span>#> $ a : num 12</span><span>
</span><span>#> $ b : num -100</span><span>
</span><span>#> $ .metadata: list()</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span></code></pre>
</div>
</div>
<h2>Time for some <em>extra</em> nonstandard evaluation</h2>
<p>The code so far only works if the machine already has registers that match the<br>
registers in an instruction. Otherwise, we raise an error.</p>
<div>
<div>
<pre><code><span>create_register_machine</span><span>()</span><span> </span><span>%>%</span><span> </span><span>eval_instruction</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>a</span><span> </span><span>></span><span> </span><span>1</span><span>)</span><span> </span><span>b</span><span> </span><span>-</span><span> </span><span>100</span><span> </span><span>else</span><span> </span><span>b</span><span>))</span><span>
</span><span>#> Error in overscope_eval_next(overscope, expr): object 'a' not found</span><span>
</span><span># &quot;Overscope&quot; is the tidy evaluation term for the data context, so failing to</span><span>
</span><span># find the name in the data is failing to find the name in the overscope.</span><span>
</span></code></pre>
</div>
</div>
<p>To solve the problem, we could study the 1,000 lines of input beforehand,<br>
extract the register names, initialize them to 0 and then evaluate the<br>
instructions.<sup><a rel="nofollow" href="https://tjmahr.github.io/nonstandard-eval-register-machines/#fn:starthere" target="_blank">1</a></sup> Or… or… we could procrastinate and only<br>
initialize a register name to 0 when the machine encounters a name it doesn’t<br>
recognize. If, for some reason, our machine received instructions<br>
one at a time, like over a network connection, then the procrastinated approach<br>
seems even more reasonable.</p>
<p>This latter strategy will involve some <em>very</em> nonstandard evaluation. I<br>
emphasize the “very” because <strong>we are changing one of the fundamental rules of R<br>
evaluation</strong> :smiling_imp:. R throws an error if you ask it to evaluate the name<br>
of a variable that doesn’t exist. But here we are going to detect those missing<br>
variables and set them to 0 before they get evaluated.</p>
<p>To find the brand-new register names, we can inspect the call tree and find the<br>
names of the registers. We already know where the target is. The other place<br>
where names show up is in the condition of the <code>if</code> statement.</p>
<div>
<div>
<pre><code><span>pryr</span><span>::</span><span>call_tree</span><span>(</span><span>r_code</span><span>)</span><span>
</span><span>#> \- ()</span><span>
</span><span>#> \- `if</span><span>
</span><span>#> \- ()</span><span>
</span><span>#> \- `></span><span>
</span><span>#> \- `a</span><span>
</span><span>#> \- 1</span><span>
</span><span>#> \- ()</span><span>
</span><span>#> \- `+</span><span>
</span><span>#> \- `b</span><span>
</span><span>#> \- 5</span><span>
</span><span>#> \- `b</span><span>
</span><span>extract_register_names</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>instruction</span><span>)</span><span> </span><span>{</span><span>
</span><span>reg_target</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>as_string</span><span>(</span><span>instruction</span><span>[[</span><span>4</span><span>]])</span><span>
</span><span>reg_condition</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>as_string</span><span>(</span><span>instruction</span><span>[[</span><span>2</span><span>]][[</span><span>2</span><span>]])</span><span>
</span><span>list</span><span>(</span><span>target</span><span> </span><span>=</span><span> </span><span>reg_target</span><span>,</span><span>
</span><span>registers</span><span> </span><span>=</span><span> </span><span>unique</span><span>(</span><span>c</span><span>(</span><span>reg_target</span><span>,</span><span> </span><span>reg_condition</span><span>))</span><span>
</span><span>)</span><span>
</span><span>}</span><span>
</span><span>extract_register_names</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>a</span><span> </span><span>></span><span> </span><span>1</span><span>)</span><span> </span><span>b</span><span> </span><span>-</span><span> </span><span>100</span><span> </span><span>else</span><span> </span><span>b</span><span>))</span><span> </span><span>%>%</span><span> </span><span>str</span><span>()</span><span>
</span><span>#> List of 2</span><span>
</span><span>#> $ target : chr &quot;b&quot;</span><span>
</span><span>#> $ registers: chr [1:2] &quot;b&quot; &quot;a&quot;</span><span>
</span><span># Just returns unique names</span><span>
</span><span>extract_register_names</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>b</span><span> </span><span>></span><span> </span><span>1</span><span>)</span><span> </span><span>b</span><span> </span><span>-</span><span> </span><span>100</span><span> </span><span>else</span><span> </span><span>b</span><span>))</span><span> </span><span>%>%</span><span> </span><span>str</span><span>()</span><span>
</span><span>#> List of 2</span><span>
</span><span>#> $ target : chr &quot;b&quot;</span><span>
</span><span>#> $ registers: chr &quot;b&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>We can define a helper function which checks for missing names—names that<br>
yield <code>NULL</code> values when we try to retrieve them—and initializes them to 0.</p>
<div>
<div>
<pre><code><span>initialize_new_registers</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>register_machine</span><span>,</span><span> </span><span>registers</span><span>)</span><span> </span><span>{</span><span>
</span><span>for</span><span> </span><span>(</span><span>each_register</span><span> </span><span>in</span><span> </span><span>registers</span><span>)</span><span> </span><span>{</span><span>
</span><span>if</span><span> </span><span>(</span><span>is.null</span><span>(</span><span>register_machine</span><span>[[</span><span>each_register</span><span>]]))</span><span> </span><span>{</span><span>
</span><span>register_machine</span><span>[[</span><span>each_register</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>0</span><span>
</span><span>}</span><span>
</span><span>}</span><span>
</span><span>register_machine</span><span>
</span><span>}</span><span>
</span><span># Before</span><span>
</span><span>r</span><span>
</span><span>#> List of 3</span><span>
</span><span>#> $ a : num 4</span><span>
</span><span>#> $ b : num 12</span><span>
</span><span>#> $ .metadata: list()</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span><span>initialize_new_registers</span><span>(</span><span>r</span><span>,</span><span> </span><span>c</span><span>(</span><span>&quot;a&quot;</span><span>,</span><span> </span><span>&quot;b&quot;</span><span>,</span><span> </span><span>&quot;w&quot;</span><span>,</span><span> </span><span>&quot;a&quot;</span><span>,</span><span> </span><span>&quot;s&quot;</span><span>,</span><span> </span><span>&quot;j&quot;</span><span>))</span><span>
</span><span>#> List of 6</span><span>
</span><span>#> $ a : num 4</span><span>
</span><span>#> $ b : num 12</span><span>
</span><span>#> $ .metadata: list()</span><span>
</span><span>#> $ w : num 0</span><span>
</span><span>#> $ s : num 0</span><span>
</span><span>#> $ j : num 0</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>Finally, we update our evaluation function to do this step automatically. I’m<br>
also going to add some code to record the value of the maximum register whenever<br>
an instruction is evaluated because, ummm, that’s the whole point of puzzle.</p>
<div>
<div>
<pre><code><span>eval_instruction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>register_machine</span><span>,</span><span> </span><span>instruction</span><span>)</span><span> </span><span>{</span><span>
</span><span># Set any new registers to 0</span><span>
</span><span>registers</span><span> </span><span>&lt;-</span><span> </span><span>extract_register_names</span><span>(</span><span>instruction</span><span>)</span><span>
</span><span>register_machine</span><span> </span><span>&lt;-</span><span> </span><span>initialize_new_registers</span><span>(</span><span>
</span><span>register_machine</span><span>,</span><span> </span><span>registers</span><span>$</span><span>registers</span><span>)</span><span>
</span><span># Evaluate instruction</span><span>
</span><span>register_machine</span><span>[[</span><span>registers</span><span>$</span><span>target</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>eval_tidy</span><span>(</span><span>
</span><span>expr</span><span> </span><span>=</span><span> </span><span>instruction</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>register_machine</span><span>)</span><span>
</span><span># Find the maximum value</span><span>
</span><span>register_names</span><span> </span><span>&lt;-</span><span> </span><span>setdiff</span><span>(</span><span>names</span><span>(</span><span>register_machine</span><span>),</span><span> </span><span>&quot;.metadata&quot;</span><span>)</span><span>
</span><span>current_max</span><span> </span><span>&lt;-</span><span> </span><span>max</span><span>(</span><span>unlist</span><span>(</span><span>register_machine</span><span>[</span><span>register_names</span><span>]))</span><span>
</span><span>register_machine</span><span>$</span><span>.metadata</span><span>$</span><span>max</span><span> </span><span>&lt;-</span><span> </span><span>current_max</span><span>
</span><span>register_machine</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
</div>
<p>Let’s try four instructions from a clean slate.</p>
<div>
<div>
<pre><code><span>create_register_machine</span><span>()</span><span> </span><span>%>%</span><span> </span><span># b gets 5</span><span>
</span><span>eval_instruction</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>d</span><span> </span><span></span><span> </span><span>1</span><span>)</span><span> </span><span>b</span><span> </span><span>+</span><span> </span><span>5</span><span> </span><span>else</span><span> </span><span>b</span><span>))</span><span> </span><span>%>%</span><span> </span><span># c gets 10</span><span>
</span><span>eval_instruction</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>b</span><span> </span><span>></span><span> </span><span>1</span><span>)</span><span> </span><span>c</span><span> </span><span>+</span><span> </span><span>10</span><span> </span><span>else</span><span> </span><span>c</span><span>))</span><span> </span><span>%>%</span><span> </span><span># b gets 5 more</span><span>
</span><span>eval_instruction</span><span>(</span><span>quote</span><span>(</span><span>if</span><span> </span><span>(</span><span>a</span><span> </span><span></span><span> </span><span>1</span><span>)</span><span> </span><span>b</span><span> </span><span>+</span><span> </span><span>5</span><span> </span><span>else</span><span> </span><span>b</span><span>))</span><span>
</span><span>#> List of 5</span><span>
</span><span>#> $ .metadata:List of 1</span><span>
</span><span>#> ..$ max: num 10</span><span>
</span><span>#> $ b : num 10</span><span>
</span><span>#> $ d : num 0</span><span>
</span><span>#> $ c : num 10</span><span>
</span><span>#> $ a : num 0</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>Now, for the moment of truth… Let’s process all 1,000 instructions.</p>
<div>
<div>
<pre><code><span>r</span><span> </span><span>&lt;-</span><span> </span><span>create_register_machine</span><span>()</span><span>
</span><span>for</span><span> </span><span>(</span><span>each_instruction</span><span> </span><span>in</span><span> </span><span>full_input</span><span>)</span><span> </span><span>{</span><span>
</span><span>parsed</span><span> </span><span>&lt;-</span><span> </span><span>each_instruction</span><span> </span><span>%>%</span><span> </span><span>parse_instruction</span><span>()</span><span> </span><span>%>%</span><span> </span><span>create_r_instruction</span><span>()</span><span>
</span><span>r</span><span> </span><span>&lt;-</span><span> </span><span>eval_instruction</span><span>(</span><span>r</span><span>,</span><span> </span><span>parsed</span><span>)</span><span>
</span><span>}</span><span>
</span><span>r</span><span>
</span><span>#> List of 27</span><span>
</span><span>#> $ .metadata:List of 1</span><span>
</span><span>#> ..$ max: num 4832</span><span>
</span><span>#> $ kd : num -2334</span><span>
</span><span>#> $ gm : num -4239</span><span>
</span><span>#> $ x : num -345</span><span>
</span><span>#> $ kjn : num -1813</span><span>
</span><span>#> $ ey : num 209</span><span>
</span><span>#> $ n : num -764</span><span>
</span><span>#> $ t : num 2997</span><span>
</span><span>#> $ f : num 4468</span><span>
</span><span>#> $ msg : num -3906</span><span>
</span><span>#> $ ic : num -263</span><span>
</span><span>#> $ zv : num -599</span><span>
</span><span>#> $ gub : num 2025</span><span>
</span><span>#> $ yp : num -2530</span><span>
</span><span>#> $ lyr : num -2065</span><span>
</span><span>#> $ j : num 3619</span><span>
</span><span>#> $ e : num -4230</span><span>
</span><span>#> $ riz : num 863</span><span>
</span><span>#> $ lzd : num 4832</span><span>
</span><span>#> $ ucy : num -3947</span><span>
</span><span>#> $ i : num 3448</span><span>
</span><span>#> $ omz : num -3365</span><span>
</span><span>#> $ djq : num 392</span><span>
</span><span>#> $ bxy : num 1574</span><span>
</span><span>#> $ tj : num 1278</span><span>
</span><span>#> $ y : num 1521</span><span>
</span><span>#> $ m : num 2571</span><span>
</span><span>#> - attr(*, &quot;class&quot;)= chr [1:2] &quot;register_machine&quot; &quot;list&quot;</span><span>
</span></code></pre>
</div>
</div>
<p>:star: Ta-da! The maximum register value is 4,832. <strong>Problem solved!</strong></p>
<h2>And then the rules change</h2>
<p>Advent of Code problems come in two parts, and we don’t learn the question<br>
behind Part 2 until we complete Part 1. In this case, after submitting our<br>
solution for Part 1, we receive the following requirement:</p>
<blockquote>
<p>To be safe, the CPU also needs to know <strong>the highest value held in any<br>
register during this process</strong> so that it can decide how much memory to allocate<br>
to these operations.</p>
</blockquote>
<p>Accounting for this twist requires a small change to the evaluation code. We<br>
add another metadata variable to track the highest value ever stored in a<br>
register.</p>
<div>
<div>
<pre><code><span>eval_instruction</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>register_machine</span><span>,</span><span> </span><span>instruction</span><span>)</span><span> </span><span>{</span><span>
</span><span># Set any new registers to 0</span><span>
</span><span>registers</span><span> </span><span>&lt;-</span><span> </span><span>extract_register_names</span><span>(</span><span>instruction</span><span>)</span><span>
</span><span>register_machine</span><span> </span><span>&lt;-</span><span> </span><span>initialize_new_registers</span><span>(</span><span>
</span><span>register_machine</span><span>,</span><span> </span><span>registers</span><span>$</span><span>registers</span><span>)</span><span>
</span><span># Evaluate instruction</span><span>
</span><span>register_machine</span><span>[[</span><span>registers</span><span>$</span><span>target</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>rlang</span><span>::</span><span>eval_tidy</span><span>(</span><span>
</span><span>expr</span><span> </span><span>=</span><span> </span><span>instruction</span><span>,</span><span> </span><span>data</span><span> </span><span>=</span><span> </span><span>register_machine</span><span>)</span><span>
</span><span># Find the maximum value</span><span>
</span><span>register_names</span><span> </span><span>&lt;-</span><span> </span><span>setdiff</span><span>(</span><span>names</span><span>(</span><span>register_machine</span><span>),</span><span> </span><span>&quot;.metadata&quot;</span><span>)</span><span>
</span><span>current_max</span><span> </span><span>&lt;-</span><span> </span><span>max</span><span>(</span><span>unlist</span><span>(</span><span>register_machine</span><span>[</span><span>register_names</span><span>]))</span><span>
</span><span>register_machine</span><span>$</span><span>.metadata</span><span>$</span><span>max</span><span> </span><span>&lt;-</span><span> </span><span>current_max</span><span>
</span><span># Create the max-ever value if necessary</span><span>
</span><span>if</span><span> </span><span>(</span><span>is.null</span><span>(</span><span>register_machine</span><span>$</span><span>.metadata</span><span>$</span><span>max_ever</span><span>))</span><span> </span><span>{</span><span>
</span><span>register_machine</span><span>$</span><span>.metadata</span><span>$</span><span>max_ever</span><span> </span><span>&lt;-</span><span> </span><span>0</span><span>
</span><span>}</span><span>
</span><span># Maybe update the max-ever value</span><span>
</span><span>if</span><span> </span><span>(</span><span>register_machine</span><span>$</span><span>.metadata</span><span>$</span><span>max_ever</span><span> </span><span></span><span> </span><span>current_max</span><span>)</span><span> </span><span>{</span><span>
</span><span>register_machine</span><span>$</span><span>.metadata</span><span>$</span><span>max_ever</span><span> </span><span>&lt;-</span><span> </span><span>current_max</span><span>
</span><span>}</span><span>
</span><span>register_machine</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
</div>
<p>Admittedly, <code>eval_instruction()</code> is starting to get bloated. Conceptually, we<br>
could probably the break this function down into three functions: pre-evaluation<br>
steps, evaluation, and post-evaluation steps.<sup><a rel="nofollow" href="https://tjmahr.github.io/nonstandard-eval-register-machines/#fn:brainstorm" target="_blank">2</a></sup> But this is good<br>
enough for now.</p>
<p>We run the instructions again to get the updated metadata.</p>
<div>
<div>
<pre><code><span>r</span><span> </span><span>&lt;-</span><span> </span><span>create_register_machine</span><span>()</span><span>
</span><span>for</span><span> </span><span>(</span><span>each_instruction</span><span> </span><span>in</span><span> </span><span>full_input</span><span>)</span><span> </span><span>{</span><span>
</span><span>parsed</span><span> </span><span>&lt;-</span><span> </span><span>each_instruction</span><span> </span><span>%>%</span><span> </span><span>parse_instruction</span><span>()</span><span> </span><span>%>%</span><span> </span><span>create_r_instruction</span><span>()</span><span>
</span><span>r</span><span> </span><span>&lt;-</span><span> </span><span>eval_instruction</span><span>(</span><span>r</span><span>,</span><span> </span><span>parsed</span><span>)</span><span>
</span><span>}</span><span>
</span><span>r</span><span>$</span><span>.metadata</span><span>
</span><span>#> $max</span><span>
</span><span>#> [1] 4832</span><span>
</span><span>#> </span><span>
</span><span>#> $max_ever</span><span>
</span><span>#> [1] 5443</span><span>
</span></code></pre>
</div>
</div>
<p>:star2: And boom! <strong>Another problem solved.</strong></p>
<h2><code>eval(thoughts, envir = this_problem)</code></h2>
<p>I like this kind of nonstandard evaluation approach for converting problems into<br>
R code, but it’s mostly useful when the problem describes a series of<br>
instructions that can be parsed and evaluated. For problems like this register<br>
machine simulation, the nonstandard evaluation route is straightforward. But<br>
it’s also a viable problem-solving strategy when the “machine” or the<br>
“instructions” are subtler, as in<br>
<a rel="nofollow" href="http://adventofcode.com/2017/day/16" title="Advent of Code 2017 - Day 16" target="_blank">this problem about simulating “dance” moves</a>.</p>
<p>Odds are, you’ll never have to write an interpreter for a toy machine or<br>
language. Nevertheless, here are some R functions that we used for this<br>
puzzle that are helpful in other contexts:</p>
<ul>
<li><code>stringr::str_match()</code> to extract all the groups in a regular<br>
expression at once.</li>
<li><code>rlang::parse_expr()</code> to convert a string of text into an R expression.</li>
<li><code>pryr::call_tree()</code> to visualize an expression’s syntax tree and<br>
<code>expression[[i]][[j]]</code> to pluck out symbols from locations in a tree.</li>
<li><code>rlang::as_string()</code> to convert a symbol into a string.</li>
<li><code>rlang::eval_tidy()</code> to evaluate an expression inside of a data<br>
context.</li>
</ul>
<hr>
<div>
<ol>
<li>
<p>That actually would be pretty easy. Get a dataframe with<br>
<code>purrr::map_df(full_input, parse_instruction)</code>. Find the unique register<br>
names. Create a list of 0’s with those names. Use <code>do.call()</code> to call<br>
<code>create_register_machine()</code> with that list. With no special evaluation<br>
trickery, this approach is closer to the idea of “just running R code”. <a rel="nofollow" href="https://tjmahr.github.io/nonstandard-eval-register-machines/#fnref:starthere" target="_blank"><img alt="↩" src="https://s.w.org/images/core/emoji/2.3/72x72/21a9.png" class="wp-smiley"></a></p>
</li>
<li>
<p>If all I did for a living was write code to simulate machines<br>
or toy languages, I might try to formalize this custom evaluation process<br>
with pre-evaluation and post-evaluations “hooks” that could be arguments<br>
to a custom evaluation function. I’m just brainstorming though. <a rel="nofollow" href="https://tjmahr.github.io/nonstandard-eval-register-machines/#fnref:brainstorm" target="_blank"><img alt="↩" src="https://s.w.org/images/core/emoji/2.3/72x72/21a9.png" class="wp-smiley"></a></p>
</li>
</ol>
</div>
	<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/nonstandard-eval-register-machines/"> 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 rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/11e5M368V7w" height="1"></a></div>