Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I'm going to give you a general solution for these kind of problems.</p> <p>Most loops can be done effortlessly with a strait forward <em>map</em>, <em>filter</em> or <em>reduce</em>, and if your data structure is recursive, naturally the loop will be a recursion.</p> <p>Your loop, however, is a different kind of loop. Your loop accumulates a result -- which would suggests using <em>reduce</em> -- but the loop also carries a local variable along (<em>pc</em>), so it's not a strait reduce. </p> <p>It's a reasonably common kind of loop. If this was <a href="http://racket-lang.org" rel="nofollow">Racket</a>, I would use <a href="http://planet.plt-scheme.org/package-source/untyped/unlib.plt/3/24/planet-docs/unlib/for.html#%28form._%28%28planet._for..ss._%28untyped._unlib..plt._3._23%29%29._for/fold1%29%29" rel="nofollow">for/fold1</a>, but since it's not, we will have to shoehorn your loop onto <em>reduce</em>. </p> <p>Let's define a function called <em>load</em> which returns two things, the processed code and the processed labels. I will also use a helper function called <em>is-label?</em>.</p> <pre><code>(defn load [asm] (defn is-label? [x] (= (first x) :label)) {:code &lt;&lt;&lt; CODE GOES HERE &gt;&gt;&gt; :labels &lt;&lt;&lt; CODE GOES HERE &gt;&gt;&gt; }) </code></pre> <p>Right now, your loop does two things, it processes the code, and it processes the labels. As much as possible, I try to keep loops to a single task. It makes them easier to understand, and it often reveals opportunities for using the simpler loop constructs.</p> <p>To get the code, we simply need to remove the labels. That's a call to <em>filter</em>.</p> <pre><code> {:code (filter (complement is-label?) asm) :labels &lt;&lt;&lt; CODE GOES HERE &gt;&gt;&gt; } </code></pre> <p>Reduce normally has only one accumulator, but your loop needs two: the result, and the local variable <em>pc</em>. I will package these two into a vector which will be immediately deconstructed by the body of the loop. The two slots of the vector will be my two local variables.</p> <p>The initial values for these two variables appear as the 2nd argument to <em>reduce</em>.</p> <pre><code> (first (reduce (fn [[result, pc] inst] &lt;&lt; MORE CODE &gt;&gt; [{} 0] asm)) </code></pre> <p>(Note how the initial values for the variables are placed far from their declaration. If the body is long this can be hard to read. That's the problem Racket's <em>for/fold1</em> solves.)</p> <p>Once <em>reduce</em> returns, I call <em>first</em> to discard to the local variable <em>pc</em> and keep just the result.</p> <p>Filling the body of the loop is straight forward. If the instruction is a label, <em>assoc</em> into the result, otherwise increase <em>pc</em> by one. In either case, I construct a vector containing new values for all the local variables.</p> <pre><code> (fn [[result, pc] [_ arg :as inst]] (if (is-label? inst) [(assoc result arg pc) pc] [result (inc pc)])) </code></pre> <p>This technique can be used to convert any accumulator-with-locals loop into a <em>reduce</em>. Here's the full code.</p> <pre><code>(defn load [asm] (defn is-label? [x] (= (first x) :label)) {:code (filter (complement is-label?) asm) :labels (first (reduce (fn [[result, pc] [_ arg :as inst]] (if (is-label? inst) [(assoc result arg pc) pc] [result (inc pc)])) [{} 0] asm))}) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload