<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" version="2.0">

<channel>
	<title>Clojure and me</title>
	
	<link>http://clj-me.cgrand.net</link>
	<description>When the pupil is ready to learn, a teacher will appear.</description>
	<lastBuildDate>Thu, 20 Oct 2011 10:26:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.4</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ClojureAndMe" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="clojureandme" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Valued functions</title>
		<link>http://clj-me.cgrand.net/2011/10/17/valued-functions/</link>
		<comments>http://clj-me.cgrand.net/2011/10/17/valued-functions/#comments</comments>
		<pubDate>Mon, 17 Oct 2011 12:55:51 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=482</guid>
		<description><![CDATA[Functions are black boxes and determining when two functions are equivalent is undecidable. That&#8217;s why:(= (fn [x] x) (fn [x] x)) is false (a clever compiler could sove this naive specific case but not all). However from time to time I&#8217;d like functions constructed the same way be considered equals. For example (= (comp inc [...]]]></description>
			<content:encoded><![CDATA[<p>Functions are black boxes and determining when two functions are equivalent is undecidable. That&#8217;s why:<code class="highlight"><span class="p">(</span><span class="nb">= </span><span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">x</span><span class="p">]</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">x</span><span class="p">]</span> <span class="nv">x</span><span class="p">))</span></code> is false (a clever compiler could sove this naive specific case but not all).</p>
<p>However from time to time I&#8217;d like functions constructed the same way be considered equals. For example <code class="highlight"><span class="p">(</span><span class="nb">= </span><span class="p">(</span><span class="nb">comp </span><span class="nv">inc</span> <span class="nv">inc</span><span class="p">)</span> <span class="p">(</span><span class="nb">comp </span><span class="nv">inc</span> <span class="nv">inc</span><span class="p">))</span></code> could be true and it wouldn&#8217;t necessitate a smart enough compiler or memoization.</p>
<p>It&#8217;s not without precedent: keywords, symbols, maps, sets and vectors are functions and also have value semantics: <code class="highlight"><span class="p">(</span><span class="nb">= </span><span class="p">(</span><span class="nb">hash-set </span><span class="mi">1</span><span class="p">)</span> <span class="p">(</span><span class="nb">hash-set </span><span class="mi">1</span><span class="p">))</span></code> is true!</p>
<p>In <a href="https://github.com/cgrand/indexed-set">indexed-set</a> I use maps whose values are functions, sometimes functions returned by higher-order functions and the user having no reference to the function returned by the hof can&#8217;t look it up in the map &mdash; if she calls the hof agin with the same arguments she gets another function which is not equal to the first one. This means that I should always let the user call the hof by herself and keep the result around. It may be ok for a low-level API but not for more user-friendly functions.</p>
<p>Helpfully, records have value semantics, can implement Java interfaces and do not already implement <code class="highlight"><span class="nv">clojure</span><span class="o">.</span><span class="nv">lang</span><span class="o">.</span><span class="nv">IFn</span></code> and <a href="https://github.com/cgrand/indexed-set/blob/6031fa1e9ffdf482bdae44345752cda2217e51d4/src/net/cgrand/indexed_set/core.clj#L195">that&#8217;s what I have done</a>:
<pre class="highlight"><span class="p">(</span><span class="nf">defrecord</span> <span class="nv">Op-By</span> <span class="p">[</span><span class="nv">key</span> <span class="nv">f</span> <span class="nv">init</span><span class="p">]</span>
  <span class="nv">clojure</span><span class="o">.</span><span class="nv">lang</span><span class="o">.</span><span class="nv">IFn</span>
  <span class="p">(</span><span class="nf">invoke</span> <span class="p">[</span><span class="nv">this</span> <span class="nv">m</span> <span class="nv">v</span><span class="p">]</span>
    <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">k</span> <span class="p">(</span><span class="nb">key </span><span class="nv">v</span><span class="p">)]</span>
      <span class="p">(</span><span class="nb">assoc </span><span class="nv">m</span> <span class="nv">k</span> <span class="p">(</span><span class="nf">f</span> <span class="p">(</span><span class="nf">m</span> <span class="nv">k</span> <span class="nv">init</span><span class="p">)</span> <span class="nv">v</span><span class="p">)))))</span>

<span class="p">(</span><span class="k">defn- </span><span class="nv">op-by</span> <span class="p">[</span><span class="nv">key</span> <span class="nv">f</span> <span class="nv">init</span><span class="p">]</span> <span class="p">(</span><span class="nf">Op-By</span><span class="o">.</span> <span class="nv">key</span> <span class="nv">f</span> <span class="nv">init</span><span class="p">))</span></pre>
<p> instead of
<pre class="highlight"><span class="p">(</span><span class="k">defn- </span><span class="nv">op-by</span> <span class="p">[</span><span class="nv">key</span> <span class="nv">f</span> <span class="nv">init</span><span class="p">]</span>
  <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">m</span> <span class="nv">v</span><span class="p">])</span>
    <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">k</span> <span class="p">(</span><span class="nb">key </span><span class="nv">v</span><span class="p">)]</span>
      <span class="p">(</span><span class="nb">assoc </span><span class="nv">m</span> <span class="nv">k</span> <span class="p">(</span><span class="nf">f</span> <span class="p">(</span><span class="nf">m</span> <span class="nv">k</span> <span class="nv">init</span><span class="p">)</span> <span class="nv">v</span><span class="p">))))</span></pre>
<p>I&#8217;m still not happy with that I&#8217;d like something more fluid (closer to fn, maybe built on reify but ideally a metadata flag  on <code class="highlight"><span class="nv">fn</span></code> e.g. <code class="highlight"><span class="p">(</span><span class="nf">^:valued</span> <span class="k">fn </span><span class="p">[</span><span class="nv">m</span> <span class="nv">v</span><span class="p">]</span> <span class="o">...</span><span class="p">)</span></code>) ; I don&#8217;t think the type name is valueable, I&#8217;m on the fence concerning features I get <em>for free</em> from <code class="highlight"><span class="nv">defrecord</span></code> (namely <code class="highlight"><span class="nv">conj</span></code>, <code class="highlight"><span class="nv">assoc</span></code> and <code class="highlight"><span class="nv">dissoc</span></code>).</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/qBJvkoDdWvs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2011/10/17/valued-functions/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>A world in a ref</title>
		<link>http://clj-me.cgrand.net/2011/10/06/a-world-in-a-ref/</link>
		<comments>http://clj-me.cgrand.net/2011/10/06/a-world-in-a-ref/#comments</comments>
		<pubDate>Thu, 06 Oct 2011 11:00:30 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=463</guid>
		<description><![CDATA[At times I struggle deciding on the granularity I should give to my refs. If I put a big map in a single ref (what I call a megaref), updates to unrelated parts of the map may conflict and cause transactions to retry, but it&#8217;s dead easy to snapshot the whole state. If I use [...]]]></description>
			<content:encoded><![CDATA[<p>At times I struggle deciding on the granularity I should give to my refs. If I put a big map in a single ref (what I call a <em>megaref</em>), updates to unrelated parts of the map may conflict and cause transactions to retry, but it&#8217;s dead easy to snapshot the whole state. If I use a ref for every entry of the map, concurrency is excellent again but snapshotting the whole state may be tricky (you need to tune the ref to have a history long enough) when there is a large number of rapidly changing refs or when the system is slow/loaded.</p>
<p>What I&#8217;d like is an <code class="highlight"><span class="nv">alter-in</span></code> function, a mix of <code class="highlight"><span class="nv">alter</span></code> and <code class="highlight"><span class="nv">update-in</span></code>, with the following guarantee: <em>two <code class="highlight"><span class="nv">alter-in</span></code>s conflict when their paths are either equal or prefix from one another</em>.</p>
<p>This is not something new: this problem bugs me since 2008 I think. I had several (failed/unfinished and private) attempts to patch the STM to accommodate for a new reference type.</p>
<p>Some weeks ago I realized that I didn&#8217;t need to hack the STM to create such a new reference type.</p>
<p>The basic idea behind all my attempts was to use lock-striping. What I didn&#8217;t realize is that I can leverage the existing STM by using ref-striping!</p>
<p>Let&#8217;s say the whole map is stored in a single ref, the <em>root</em> ref and you have N guard refs (whose value is <code class="highlight"><span class="nv">nil</span></code>). When I want to alter the value for a given key, I compute its hash modulo N which gives me an index into the guards vector. I <code class="highlight"><span class="nv">ref-set</span></code> the corresponding guard ref (to <code class="highlight"><span class="nv">nil</span></code>, the actual value doesn&#8217;t matter) thus claiming exclusive commit rights for this key. Once that done I simply <code class="highlight"><span class="nv">commute</span></code> on the root ref being sure that the operation will only commute with non-conflicting other ops.</p>
<p>NB: An alternative design is to simply have N roots and no guards and to merge the N maps on <code class="highlight"><span class="nv">deref</span></code> — efficient merging would need a didcated map implementation. However it doesn&#8217;t help much with nested maps but it helps a lot with concurrency since in the other design everything is serialized on the single root. I think an hybrid solution (N roots, each roots having M guards) woud bring an interesting trade-off between concurrency, number of retries and ease of snapshotting.</p>
<p>To support nested maps, instead of a single key, one has to deal with a path, eg <code class="highlight"><span class="p">[</span><span class="nv">:a</span> <span class="nv">:b</span> <span class="nv">:c</span><span class="p">]</span></code>. Here the idea is to <code class="highlight"><span class="nv">ensure</span></code> guards for path prefixes (<code class="highlight"><span class="p">[</span><span class="nv">:a</span><span class="p">]</span></code> and <code class="highlight"><span class="p">[</span><span class="nv">:a</span> <span class="nv">:b</span><span class="p">]</span></code>) and to <code class="highlight"><span class="nv">ref-set</span></code> the guard for the full-path as before.</p>
<pre class="highlight"><span class="c1">;; except ensure-in and alter-in, the others are here because</span>
<span class="c1">;; they can be optimized in a mega ref wth several roots</span>
<span class="p">(</span><span class="nf">defprotocol</span> <span class="nv">AssociativeRef</span>
  <span class="p">(</span><span class="nf">-alter-in</span> <span class="p">[</span><span class="nv">aref</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">args</span><span class="p">])</span>
  <span class="p">(</span><span class="nf">-commute-in</span> <span class="p">[</span><span class="nv">aref</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">args</span><span class="p">])</span>
  <span class="p">(</span><span class="nf">ref-set-in</span> <span class="p">[</span><span class="nv">aref</span> <span class="nv">ks</span> <span class="nv">v</span><span class="p">])</span>
  <span class="p">(</span><span class="nf">ensure-in</span> <span class="p">[</span><span class="nv">aref</span> <span class="nv">ks</span><span class="p">])</span>
  <span class="p">(</span><span class="nf">deref-in</span> <span class="p">[</span><span class="nv">aref</span> <span class="nv">ks</span><span class="p">]))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">alter-in</span> <span class="p">[</span><span class="nv">aref</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">&amp;</span> <span class="nv">args</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">-alter-in</span> <span class="nv">aref</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">args</span><span class="p">))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">commute-in</span> <span class="p">[</span><span class="nv">aref</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">&amp;</span> <span class="nv">args</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">-commute-in</span> <span class="nv">aref</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">args</span><span class="p">))</span>

<span class="p">(</span><span class="k">defn- </span><span class="nv">ensure-path</span> <span class="p">[</span><span class="nv">guard-for</span> <span class="nv">path</span><span class="p">]</span>
  <span class="p">(</span><span class="nb">loop </span><span class="p">[</span><span class="nv">path</span> <span class="nv">path</span><span class="p">]</span>
    <span class="p">(</span><span class="nb">when-not </span><span class="p">(</span><span class="nb">= </span><span class="p">[]</span> <span class="nv">path</span><span class="p">)</span>
      <span class="p">(</span><span class="nb">ensure </span><span class="p">(</span><span class="nf">guard-for</span> <span class="nv">path</span><span class="p">))</span>
      <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">pop </span><span class="nv">path</span><span class="p">)))))</span>

<span class="p">(</span><span class="k">defn- </span><span class="nv">guards-fn</span> <span class="p">[</span><span class="nv">guards</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">n</span> <span class="p">(</span><span class="nb">count </span><span class="nv">guards</span><span class="p">)]</span>
    <span class="o">#</span><span class="p">(</span><span class="nv">nth</span> <span class="nv">guards</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nf">hash</span> <span class="nv">%</span><span class="p">)</span> <span class="nv">n</span><span class="p">))))</span>

<span class="p">(</span><span class="nf">deftype</span> <span class="nv">MegaRef</span> <span class="p">[</span><span class="nv">r</span> <span class="nv">guards</span><span class="p">]</span>
  <span class="nv">AssociativeRef</span>
  <span class="p">(</span><span class="nf">-alter-in</span> <span class="p">[</span><span class="nv">this</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">args</span><span class="p">]</span>
    <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">seq </span><span class="nv">ks</span><span class="p">)</span>
      <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">guard-for</span> <span class="p">(</span><span class="nf">guards-fn</span> <span class="nv">guards</span><span class="p">)]</span>
        <span class="p">(</span><span class="nf">ensure-path</span> <span class="nv">guard-for</span> <span class="p">(</span><span class="nb">pop </span><span class="p">(</span><span class="nf">vec</span> <span class="nv">ks</span><span class="p">)))</span>
        <span class="p">(</span><span class="nb">ref-set </span><span class="p">(</span><span class="nf">guard-for</span> <span class="nv">ks</span><span class="p">)</span> <span class="nv">nil</span><span class="p">)</span>
        <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">v</span> <span class="p">(</span><span class="nb">apply </span><span class="nv">f</span> <span class="p">(</span><span class="nf">get-in</span> <span class="nv">@r</span> <span class="nv">ks</span><span class="p">)</span> <span class="nv">args</span><span class="p">)]</span>
          <span class="c1">; v is precomputed to not evaluate it twice because of commute</span>
          <span class="p">(</span><span class="nb">commute </span><span class="nv">r</span> <span class="nv">assoc-in</span> <span class="nv">ks</span> <span class="nv">v</span><span class="p">)))</span>
      <span class="p">(</span><span class="nf">throw</span> <span class="p">(</span><span class="nf">IllegalArgumentException</span><span class="o">.</span> <span class="s">&quot;ks must not be empty.&quot;</span><span class="p">))))</span>
  <span class="p">(</span><span class="nf">-commute-in</span> <span class="p">[</span><span class="nv">this</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">args</span><span class="p">]</span>
    <span class="p">(</span><span class="nb">apply </span><span class="nv">commute</span> <span class="nv">r</span> <span class="nv">update-in</span> <span class="nv">ks</span> <span class="nv">f</span> <span class="nv">args</span><span class="p">))</span>
  <span class="p">(</span><span class="nf">ref-set-in</span> <span class="p">[</span><span class="nv">this</span> <span class="nv">ks</span> <span class="nv">v</span><span class="p">]</span>
    <span class="p">(</span><span class="nf">-alter-in</span> <span class="nv">this</span> <span class="nv">ks</span> <span class="p">(</span><span class="nb">constantly </span><span class="nv">v</span><span class="p">)</span> <span class="nv">nil</span><span class="p">))</span>
  <span class="p">(</span><span class="nf">ensure-in</span> <span class="p">[</span><span class="nv">this</span> <span class="nv">ks</span><span class="p">]</span>
    <span class="p">(</span><span class="nf">ensure-path</span>  <span class="p">(</span><span class="nf">vec</span> <span class="nv">ks</span><span class="p">)</span> <span class="p">(</span><span class="nf">guards-fn</span> <span class="nv">guards</span><span class="p">))</span>
    <span class="p">(</span><span class="nf">deref-in</span> <span class="nv">this</span> <span class="nv">ks</span><span class="p">))</span>
  <span class="p">(</span><span class="nf">deref-in</span> <span class="p">[</span><span class="nv">this</span> <span class="nv">ks</span><span class="p">]</span>
    <span class="p">(</span><span class="nf">get-in</span> <span class="nv">@r</span> <span class="nv">ks</span><span class="p">))</span>
  <span class="nv">clojure</span><span class="o">.</span><span class="nv">lang</span><span class="o">.</span><span class="nv">IDeref</span>
  <span class="p">(</span><span class="nb">deref </span><span class="p">[</span><span class="nv">this</span><span class="p">]</span>
    <span class="nv">@r</span><span class="p">))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">megaref</span> <span class="p">[</span><span class="nv">entries</span> <span class="nv">&amp;</span> <span class="nv">options</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">guards</span> <span class="p">(</span><span class="nf">:guards</span> <span class="nv">options</span> <span class="mi">16</span><span class="p">)</span>
        <span class="nv">root-options</span> <span class="p">(</span><span class="nb">select-keys </span><span class="nv">options</span> <span class="p">[</span><span class="nv">:validator</span> <span class="nv">:min-history</span> <span class="nv">:max-history</span><span class="p">])]</span>
    <span class="p">(</span><span class="nf">MegaRef</span><span class="o">.</span> <span class="p">(</span><span class="nb">apply </span><span class="nv">ref</span> <span class="p">(</span><span class="nb">into </span><span class="p">{}</span> <span class="nv">entries</span><span class="p">)</span> <span class="nv">root-options</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">vec</span> <span class="p">(</span><span class="nf">repeatedly</span> <span class="nv">guards</span> <span class="o">#</span><span class="p">(</span><span class="nv">ref</span> <span class="nv">nil</span><span class="p">))))))</span></pre>
<p>NB: Write skew anomalies can now occur at the &#8220;sub ref&#8221; level: when you <code class="highlight"><span class="nv">deref-in</span></code> a path unrelated to the ones you update; <code class="highlight"><span class="nv">ensure-in</span></code> is the answer.</p>
<p>So, some questions:</p>
<ul>
<li>Is this of interest to anyone except me? If yes, once mature (eg multiroot) should it belong in contrib?</li>
<li>Is my implementation sound? Do I rely on implementation details?</li>
<li>Should the STM expose a &#8220;token&#8221; facility so that I don&#8217;t have to use refs as guards?</li>
</ul>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/0CrtyBqtOBI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2011/10/06/a-world-in-a-ref/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Conway’s Game of Life</title>
		<link>http://clj-me.cgrand.net/2011/08/19/conways-game-of-life/</link>
		<comments>http://clj-me.cgrand.net/2011/08/19/conways-game-of-life/#comments</comments>
		<pubDate>Fri, 19 Aug 2011 18:01:54 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=447</guid>
		<description><![CDATA[APL is famous for having a 1-liner for Conway&#8217;s game of life. Being very efficient at implementing a matrix-based solution of Conway&#8217;s game of life should come to no suprise from an array-oriented language. The way you model data determines your code. Clojure encourages what I call relational-oriented programming. That is modeling with sets, natural [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/APL_%28programming_language%29">APL</a> is famous for having a 1-liner for Conway&#8217;s game of life.<br />
Being very efficient at implementing a matrix-based solution of Conway&#8217;s game of life should come to no suprise from an array-oriented language.</p>
<p>The way you model data determines your code. Clojure encourages what I call relational-oriented programming. That is modeling with sets, natural identifiers (thanks to composite values) and maps-as-indexes.</p>
<p>If you pick the right representation for the state of the board, you end up with a succinct implementation: </p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">neighbours</span> <span class="p">[[</span><span class="nv">x</span> <span class="nv">y</span><span class="p">]]</span>
  <span class="p">(</span><span class="k">for </span><span class="p">[</span><span class="nv">dx</span> <span class="p">[</span><span class="mi">-1</span> <span class="mi">0</span> <span class="mi">1</span><span class="p">]</span> <span class="nv">dy</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">zero? </span><span class="nv">dx</span><span class="p">)</span> <span class="p">[</span><span class="mi">-1</span> <span class="mi">1</span><span class="p">]</span> <span class="p">[</span><span class="mi">-1</span> <span class="mi">0</span> <span class="mi">1</span><span class="p">])]</span>
    <span class="p">[(</span><span class="nb">+ </span><span class="nv">dx</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nb">+ </span><span class="nv">dy</span> <span class="nv">y</span><span class="p">)]))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">step</span> <span class="p">[</span><span class="nv">cells</span><span class="p">]</span>
  <span class="p">(</span><span class="nb">set </span><span class="p">(</span><span class="k">for </span><span class="p">[[</span><span class="nv">loc</span> <span class="nv">n</span><span class="p">]</span> <span class="p">(</span><span class="nf">frequencies</span> <span class="p">(</span><span class="nb">mapcat </span><span class="nv">neighbours</span> <span class="nv">cells</span><span class="p">))</span>
             <span class="nv">:when</span> <span class="p">(</span><span class="nb">or </span><span class="p">(</span><span class="nb">= </span><span class="nv">n</span> <span class="mi">3</span><span class="p">)</span> <span class="p">(</span><span class="nb">and </span><span class="p">(</span><span class="nb">= </span><span class="nv">n</span> <span class="mi">2</span><span class="p">)</span> <span class="p">(</span><span class="nf">cells</span> <span class="nv">loc</span><span class="p">)))]</span>
         <span class="nv">loc</span><span class="p">)))</span></pre>
<p>Let&#8217;s see how it behaves with the <a href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Examples_of_patterns">&#8220;blinker&#8221;</a> configuration:</p>
<pre class="highlight"><span class="p">(</span><span class="k">def </span><span class="nv">board</span> <span class="o">#</span><span class="p">{[</span><span class="mi">1</span> <span class="mi">0</span><span class="p">]</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">1</span><span class="p">]</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">2</span><span class="p">]})</span>
<span class="c1">; #&#39;user/board</span>
<span class="p">(</span><span class="nb">take </span><span class="mi">5</span> <span class="p">(</span><span class="nb">iterate </span><span class="nv">step</span> <span class="nv">board</span><span class="p">))</span>
<span class="c1">; (#{[1 0] [1 1] [1 2]} #{[2 1] [1 1] [0 1]} #{[1 0] [1 1] [1 2]} #{[2 1] [1 1] [0 1]} #{[1 0] [1 1] [1 2]})</span></pre>
<p>Great, it oscillates as expected!</p>
<p>From this <code class="highlight"><span class="nv">step</span></code> can be distilled a generic topology-agnostic life-like automatons stepper factory (phew!) but this is a subject for another post or &mdash; shameless plug &mdash; <a href="http://oreilly.com/catalog/0636920013754/">a book</a>. </p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/O4-uoXdruFU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2011/08/19/conways-game-of-life/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>A flatter cond</title>
		<link>http://clj-me.cgrand.net/2011/06/17/a-flatter-cond/</link>
		<comments>http://clj-me.cgrand.net/2011/06/17/a-flatter-cond/#comments</comments>
		<pubDate>Fri, 17 Jun 2011 12:44:46 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[utilities]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=449</guid>
		<description><![CDATA[Long time, no post. I&#8217;ve had two hiatus (one of this kind and one of that kind) and I&#8217;m still going through the pile of accumulated work (including the bird book &#8212; it&#8217;s a painted snipe). To warm up, a little macro I find quite handy: (ns flatter.cond (:refer-clojure :exclude [cond])) (defmacro cond &#34;A variation [...]]]></description>
			<content:encoded><![CDATA[<p>Long time, no post. I&#8217;ve had two hiatus (one of <a href="http://disclojure.org/2011/05/08/this-weekend-in-the-intertweets-may-8th-edition/">this kind</a> and one of <a href="http://en.wikipedia.org/wiki/Spinal_disc_herniation#Surgical">that kind</a>) and I&#8217;m still going through the pile of accumulated work (including <a href="http://oreilly.com/catalog/0636920013754/">the bird book</a> &mdash; it&#8217;s a <a href="http://en.wikipedia.org/wiki/Painted_snipe">painted snipe</a>).</p>
<p>To warm up, a little macro I find quite handy:</p>
<pre class="highlight"><span class="p">(</span><span class="nf">ns</span> <span class="nv">flatter</span><span class="o">.</span><span class="nv">cond</span>
  <span class="p">(</span><span class="nf">:refer-clojure</span> <span class="nv">:exclude</span> <span class="p">[</span><span class="nv">cond</span><span class="p">]))</span>

<span class="p">(</span><span class="k">defmacro cond </span>
  <span class="s">&quot;A variation on cond which sports let bindings:</span>
<span class="s">     (cond </span>
<span class="s">       (odd? a) 1</span>
<span class="s">       :let [a (quot a 2)]</span>
<span class="s">       (odd? a) 2</span>
<span class="s">       :else 3)&quot;</span>
  <span class="p">[</span><span class="nv">&amp;</span> <span class="nv">clauses</span><span class="p">]</span>
  <span class="p">(</span><span class="nb">when-let </span><span class="p">[[</span><span class="nv">test</span> <span class="nv">expr</span> <span class="nv">&amp;</span> <span class="nv">clauses</span><span class="p">]</span> <span class="p">(</span><span class="nb">seq </span><span class="nv">clauses</span><span class="p">)]</span>
    <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">= </span><span class="nv">:let</span> <span class="nv">test</span><span class="p">)</span>
      <span class="o">`</span><span class="p">(</span><span class="k">let </span><span class="nv">~expr</span> <span class="p">(</span><span class="k">cond </span><span class="nv">~@clauses</span><span class="p">))</span>
      <span class="o">`</span><span class="p">(</span><span class="k">if </span><span class="nv">~test</span> <span class="nv">~expr</span> <span class="p">(</span><span class="k">cond </span><span class="nv">~@clauses</span><span class="p">)))))</span></pre>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/NFUfehVcQIk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2011/06/17/a-flatter-cond/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>A* in Clojure</title>
		<link>http://clj-me.cgrand.net/2010/09/04/a-in-clojure/</link>
		<comments>http://clj-me.cgrand.net/2010/09/04/a-in-clojure/#comments</comments>
		<pubDate>Sat, 04 Sep 2010 02:22:48 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=440</guid>
		<description><![CDATA[Thanks to Mark Engelberg there&#8217;s now a nice priority map in contrib. With such a facility, it becomes really easy to write a nice implementation of the A* algorithm. (ns net.cgrand.clj-me.a-star (:use [clojure.contrib.priority-map :only [priority-map]])) (defn A* &#34;Finds a path between start and goal inside the graph described by edges (a map of edge to [...]]]></description>
			<content:encoded><![CDATA[<p>Thanks to Mark Engelberg there&#8217;s now a nice <a href="http://github.com/clojure/clojure-contrib/blob/master/modules/priority-map/src/main/clojure/clojure/contrib/priority_map.clj">priority map in contrib</a>. With such a facility, it becomes really easy to write a nice implementation of the <a href="http://en.wikipedia.org/wiki/A*_search_algorithm">A* algorithm</a>.</p>
<pre class="highlight"><span class="p">(</span><span class="nf">ns</span> <span class="nv">net</span><span class="o">.</span><span class="nv">cgrand</span><span class="o">.</span><span class="nv">clj-me</span><span class="o">.</span><span class="nv">a-star</span>
  <span class="p">(</span><span class="nf">:use</span> <span class="p">[</span><span class="nv">clojure</span><span class="o">.</span><span class="nv">contrib</span><span class="o">.</span><span class="nv">priority-map</span> <span class="nv">:only</span> <span class="p">[</span><span class="nv">priority-map</span><span class="p">]]))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">A*</span>
 <span class="s">&quot;Finds a path between start and goal inside the graph described by edges</span>
<span class="s">  (a map of edge to distance); estimate is an heuristic for the actual</span>
<span class="s">  distance. Accepts a named option: :monotonic (default to true).</span>
<span class="s">  Returns the path if found or nil.&quot;</span>
 <span class="p">[</span><span class="nv">edges</span> <span class="nv">estimate</span> <span class="nv">start</span> <span class="nv">goal</span> <span class="nv">&amp;</span> <span class="p">{</span><span class="nv">mono</span> <span class="nv">:monotonic</span> <span class="nv">:or</span> <span class="p">{</span><span class="nv">mono</span> <span class="nv">true</span><span class="p">}}]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">f</span> <span class="p">(</span><span class="nf">memoize</span> <span class="o">#</span><span class="p">(</span><span class="nv">estimate</span> <span class="nv">%</span> <span class="nv">goal</span><span class="p">))</span> <span class="c1">; unsure the memoization is worthy</span>
        <span class="nv">neighbours</span> <span class="p">(</span><span class="nb">reduce </span><span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">m</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]]</span> <span class="p">(</span><span class="nb">assoc </span><span class="nv">m</span> <span class="nv">a</span> <span class="p">(</span><span class="nb">conj </span><span class="p">(</span><span class="nf">m</span> <span class="nv">a</span> <span class="o">#</span><span class="p">{})</span> <span class="nv">b</span><span class="p">)))</span>
                      <span class="p">{}</span> <span class="p">(</span><span class="nb">keys </span><span class="nv">edges</span><span class="p">))]</span>
    <span class="p">(</span><span class="nb">loop </span><span class="p">[</span><span class="nv">q</span> <span class="p">(</span><span class="nf">priority-map</span> <span class="nv">start</span> <span class="p">(</span><span class="nf">f</span> <span class="nv">start</span><span class="p">))</span>
           <span class="nv">preds</span> <span class="p">{}</span>
           <span class="nv">shortest</span> <span class="p">{</span><span class="nv">start</span> <span class="mi">0</span><span class="p">}</span>
           <span class="nv">done</span> <span class="o">#</span><span class="p">{}]</span>
      <span class="p">(</span><span class="nb">when-let </span><span class="p">[[</span><span class="nv">x</span> <span class="nv">hx</span><span class="p">]</span> <span class="p">(</span><span class="nb">peek </span><span class="nv">q</span><span class="p">)]</span>
        <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">= </span><span class="nv">goal</span> <span class="nv">x</span><span class="p">)</span>
          <span class="p">(</span><span class="nb">reverse </span><span class="p">(</span><span class="nb">take-while </span><span class="nv">identity</span> <span class="p">(</span><span class="nb">iterate </span><span class="nv">preds</span> <span class="nv">goal</span><span class="p">)))</span>
          <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">dx</span> <span class="p">(</span><span class="nb">- </span><span class="nv">hx</span> <span class="p">(</span><span class="nf">f</span> <span class="nv">x</span><span class="p">))</span>
                <span class="nv">bn</span> <span class="p">(</span><span class="k">for </span><span class="p">[</span><span class="nv">n</span> <span class="p">(</span><span class="nb">remove </span><span class="nv">done</span> <span class="p">(</span><span class="nf">neighbours</span> <span class="nv">x</span><span class="p">))</span>
                         <span class="nv">:let</span> <span class="p">[</span><span class="nv">hn</span> <span class="p">(</span><span class="nb">+ </span><span class="nv">dx</span> <span class="p">(</span><span class="nf">edges</span> <span class="p">[</span><span class="nv">x</span> <span class="nv">n</span><span class="p">])</span> <span class="p">(</span><span class="nf">f</span> <span class="nv">n</span><span class="p">))</span>
                               <span class="nv">sn</span> <span class="p">(</span><span class="nf">shortest</span> <span class="nv">n</span> <span class="nv">Double/POSITIVE_INFINITY</span><span class="p">)]</span>
                         <span class="nv">:when</span> <span class="p">(</span><span class="nb">&lt; </span><span class="nv">hn</span> <span class="nv">sn</span><span class="p">)]</span>
                     <span class="p">[</span><span class="nv">n</span> <span class="nv">hn</span><span class="p">])]</span>
            <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">into </span><span class="p">(</span><span class="nb">pop </span><span class="nv">q</span><span class="p">)</span> <span class="nv">bn</span><span class="p">)</span>
              <span class="p">(</span><span class="nb">into </span><span class="nv">preds</span> <span class="p">(</span><span class="k">for </span><span class="p">[[</span><span class="nv">n</span><span class="p">]</span> <span class="nv">bn</span><span class="p">]</span> <span class="p">[</span><span class="nv">n</span> <span class="nv">x</span><span class="p">]))</span>
              <span class="p">(</span><span class="nb">into </span><span class="nv">shortest</span> <span class="nv">bn</span><span class="p">)</span>
              <span class="p">(</span><span class="k">if </span><span class="nv">mono</span> <span class="p">(</span><span class="nb">conj </span><span class="nv">done</span> <span class="nv">x</span><span class="p">)</span> <span class="nv">done</span><span class="p">))))))))</span></pre>
<p>Example:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">euclidian-distance</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]</span> <span class="c1">; multidimensional</span>
  <span class="p">(</span><span class="nf">Math/sqrt</span> <span class="p">(</span><span class="nb">reduce </span><span class="nv">+</span> <span class="p">(</span><span class="nb">map </span><span class="o">#</span><span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">c</span> <span class="p">(</span><span class="nb">- </span><span class="nv">%1</span> <span class="nv">%2</span><span class="p">)]</span> <span class="p">(</span><span class="nb">* </span><span class="nv">c</span> <span class="nv">c</span><span class="p">))</span> <span class="nv">a</span> <span class="nv">b</span><span class="p">))))</span>

<span class="c1">;; generate a grid graph whose outlying edges are one-way</span>
<span class="p">(</span><span class="k">defn </span><span class="nv">grid</span> <span class="p">[</span><span class="nv">x</span> <span class="nv">y</span> <span class="nv">w</span> <span class="nv">h</span><span class="p">]</span>
  <span class="p">(</span><span class="nb">into </span><span class="p">{}</span>
    <span class="p">(</span><span class="k">for </span><span class="p">[</span><span class="nv">i</span> <span class="p">(</span><span class="nb">range </span><span class="nv">w</span><span class="p">)</span> <span class="nv">j</span> <span class="p">(</span><span class="nb">range </span><span class="nv">h</span><span class="p">)</span>
          <span class="nv">:let</span> <span class="p">[</span><span class="nv">x0</span> <span class="p">(</span><span class="nb">+ </span><span class="nv">x</span> <span class="nv">i</span><span class="p">)</span> <span class="nv">y0</span> <span class="p">(</span><span class="nb">+ </span><span class="nv">y</span> <span class="nv">j</span><span class="p">)</span> <span class="nv">x1</span> <span class="p">(</span><span class="nb">inc </span><span class="nv">x0</span><span class="p">)</span> <span class="nv">y1</span> <span class="p">(</span><span class="nb">inc </span><span class="nv">y0</span><span class="p">)]]</span>
      <span class="p">{[[</span><span class="nv">x0</span> <span class="nv">y0</span><span class="p">]</span> <span class="p">[</span><span class="nv">x1</span> <span class="nv">y0</span><span class="p">]]</span> <span class="mi">1</span>
       <span class="p">[[</span><span class="nv">x1</span> <span class="nv">y0</span><span class="p">]</span> <span class="p">[</span><span class="nv">x1</span> <span class="nv">y1</span><span class="p">]]</span> <span class="mi">1</span>
       <span class="p">[[</span><span class="nv">x1</span> <span class="nv">y1</span><span class="p">]</span> <span class="p">[</span><span class="nv">x0</span> <span class="nv">y1</span><span class="p">]]</span> <span class="mi">1</span>
       <span class="p">[[</span><span class="nv">x0</span> <span class="nv">y1</span><span class="p">]</span> <span class="p">[</span><span class="nv">x0</span> <span class="nv">y0</span><span class="p">]]</span> <span class="mi">1</span><span class="p">})))</span>

<span class="p">(</span><span class="k">def </span><span class="nv">g</span> <span class="p">(</span><span class="nb">apply </span><span class="nv">dissoc</span> <span class="p">(</span><span class="nf">grid</span> <span class="mi">0</span> <span class="mi">0</span> <span class="mi">4</span> <span class="mi">4</span><span class="p">)</span> <span class="p">(</span><span class="nb">keys </span><span class="p">(</span><span class="nf">grid</span> <span class="mi">1</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">2</span><span class="p">))))</span>

<span class="p">(</span><span class="nb">comment </span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">A*</span> <span class="nv">g</span> <span class="nv">euclidian-distance</span> <span class="p">[</span><span class="mi">0</span> <span class="mi">3</span><span class="p">]</span> <span class="p">[</span><span class="mi">4</span> <span class="mi">2</span><span class="p">])</span>
<span class="p">([</span><span class="mi">0</span> <span class="mi">3</span><span class="p">]</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">3</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span> <span class="mi">3</span><span class="p">]</span> <span class="p">[</span><span class="mi">3</span> <span class="mi">3</span><span class="p">]</span> <span class="p">[</span><span class="mi">3</span> <span class="mi">2</span><span class="p">]</span> <span class="p">[</span><span class="mi">4</span> <span class="mi">2</span><span class="p">])</span>
<span class="p">)</span></pre>
<p>Shameless plug: if you are in Europe and want to learn Clojure, don&#8217;t forget to register for <a href="http://conj-labs.eu/">the course Lau and me will be giving in Frankfurt, October 26-28</a>.</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/JGr_BmsLypQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/09/04/a-in-clojure/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Quick update</title>
		<link>http://clj-me.cgrand.net/2010/08/26/quick-update/</link>
		<comments>http://clj-me.cgrand.net/2010/08/26/quick-update/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 22:05:50 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/2010/08/26/quick-update/</guid>
		<description><![CDATA[Long time no post. No code in this one though. However I&#8217;m pleased to announce that Lau and me are going to give another Clojure course: October 26-28 in Frankfurt, beginners welcome. So if you want to learn Clojure, register!]]></description>
			<content:encoded><![CDATA[<p>Long time no post. No code in this one though.<br />
However I&#8217;m pleased to announce that <a href="http://bestinclass.dk/">Lau</a> and me are going to give another <a href="http://conj-labs.eu/">Clojure course</a>: October 26-28 in Frankfurt, beginners welcome. So if you want to learn Clojure, register!</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/ggv9xIVtFH4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/08/26/quick-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Primitive types support for fns coming to a Clojure branch near you</title>
		<link>http://clj-me.cgrand.net/2010/06/10/primitive-types-support-for-fns-coming-to-a-clojure-branch-near-you/</link>
		<comments>http://clj-me.cgrand.net/2010/06/10/primitive-types-support-for-fns-coming-to-a-clojure-branch-near-you/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 06:57:32 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=382</guid>
		<description><![CDATA[Rich Hickey is working on primitive support in the prim branch. As of now, one can write: (defn ^:static fib ^long [^long n] (if (&#62;= (long 1) n) (long 1) (+ (fib (dec n)) (fib (- n (long 2)))))) and computes (fib 38) on my laptop in 650ms where my (or even Rich&#8217;s) best attempt [...]]]></description>
			<content:encoded><![CDATA[<p>Rich Hickey is working on primitive support in <a href="http://github.com/richhickey/clojure/commits/prim">the <code>prim</code> branch</a>. As of now, one can write:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">^:static</span> <span class="nv">fib</span> <span class="nv">^long</span> <span class="p">[</span><span class="nv">^long</span> <span class="nv">n</span><span class="p">]</span>
  <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">&gt;= </span><span class="p">(</span><span class="nb">long </span><span class="mi">1</span><span class="p">)</span> <span class="nv">n</span><span class="p">)</span>
    <span class="p">(</span><span class="nb">long </span><span class="mi">1</span><span class="p">)</span>
    <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">fib</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">n</span><span class="p">))</span> <span class="p">(</span><span class="nf">fib</span> <span class="p">(</span><span class="nb">- </span><span class="nv">n</span> <span class="p">(</span><span class="nb">long </span><span class="mi">2</span><span class="p">))))))</span></pre>
<p>and computes (fib 38) on my laptop in 650ms where my (or even Rich&#8217;s) best <a href="http://clj-me.cgrand.net/2010/06/04/primitive-support-for-fns/">attempt took about 2s!</a> If I tweak the above code to use unchecked ops (regular arithmetic ops on primitive types in Clojure throw an exception on overflow, unchecked ones don&#8217;t), the performance comes real real close (< 5%) to the equivalent Java code.</p>
<h2>What&#8217;s this <code class="highlight"><span class="nv">^:static</span></code> thing?</h2>
<p>Primitive (double and long only: they subsume any other type) args and return values are only allowed on <i>statics</i> (note that the return type hint is put on the arglist so as to allow different hints for different arities). Statics are still fns in vars but they are backed by a static method and, when called by name, a direct static method call is emitted rather than going through the var and the <ode lang="java">IFn</code> interface &mdash; as such static calls replace direct binding.</p>
<pre class="highlight"><span class="p">(</span><span class="nf">my-static</span> <span class="mi">42</span><span class="p">)</span> <span class="c1">; direct call</span>
<span class="p">(</span><span class="nb">apply </span><span class="nv">my-static</span> <span class="mi">42</span> <span class="nv">nil</span><span class="p">)</span> <span class="c1">; regular call through the var</span></pre>
<p>About the syntax: <code class="highlight"><span class="nv">^:keyword</span></code> is a new reader shorthand for <code class="highlight"><span class="nv">^</span><span class="p">{</span><span class="nv">:keyword</span> <span class="nv">true</span><span class="p">}</span></code> (and keep in mind that in Clojure 1.2 <code class="highlight"><span class="nv">^</span></code> is the new <code class="highlight"><span class="o">#</span><span class="nv">^</span></code>), and metadata are merged: <code class="highlight"><span class="nv">^:static</span> <span class="nv">^long</span> <span class="nv">^</span><span class="p">{</span><span class="nv">:doc</span> <span class="s">&quot;docstring&quot;</span><span class="p">}</span> <span class="nv">x</span></code> is now equivalent to <code class="highlight"><span class="nv">^</span><span class="p">{</span><span class="nv">:static</span> <span class="nv">true</span> <span class="nv">:tag</span> <span class="nv">long</span> <span class="nv">:doc</span> <span class="s">&quot;docstring&quot;</span><span class="p">}</span> <span class="nv">x</span></code>.</p>
<p>Interesting times... as usual in the Clojure community. Thanks Rich!</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/7bn3d-ZxMNg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/06/10/primitive-types-support-for-fns-coming-to-a-clojure-branch-near-you/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Primitive types support for fns</title>
		<link>http://clj-me.cgrand.net/2010/06/04/primitive-support-for-fns/</link>
		<comments>http://clj-me.cgrand.net/2010/06/04/primitive-support-for-fns/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 08:25:16 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=368</guid>
		<description><![CDATA[Follow up See here. Update: I was wrong and Rich Hickey set me right: I didn&#8217;t measure the gains I&#8217;m expecting because the inline-expanded form still go through the var lookup. See here (or the comments) for real gains (around 800ms on my laptop). This is a quick and dirty hack to emulate primitive types [...]]]></description>
			<content:encoded><![CDATA[<p><b>Follow up</b> <a href="http://clj-me.cgrand.net/2010/06/10/primitive-types-support-for-fns-coming-to-a-clojure-branch-near-you/">See here.</a><br />
<hr/>
<p><b>Update:</b> I was wrong and Rich Hickey <a href="http://clojure-log.n01se.net/date/2010-06-04.html#06:57-08:28">set me right</a>: I didn&#8217;t measure the gains I&#8217;m expecting because the inline-expanded form still go through the var lookup. <a href="http://gist.github.com/425352#comments">See here</a> (or <a href="http://gist.github.com/425352#gistcomment-3339">the comments</a>) for real gains (around 800ms on my laptop).<br />
<hr/>
<p>This is a quick and dirty hack to emulate primitive types support for globally-bound fns:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defmacro </span><span class="nv">defhintedfn</span> <span class="p">[</span><span class="nv">name</span> <span class="nv">args</span> <span class="nv">&amp;</span> <span class="nv">body</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">iface</span> <span class="p">(</span><span class="nb">gensym </span><span class="s">&quot;HintedFn&quot;</span><span class="p">)</span>
        <span class="nv">hname</span> <span class="p">(</span><span class="nf">vary-meta</span> <span class="nv">name</span> <span class="nv">assoc</span> <span class="nv">:tag</span> <span class="nv">iface</span><span class="p">)</span>
        <span class="nv">vname</span> <span class="p">(</span><span class="nf">vary-meta</span> <span class="nv">name</span> <span class="nv">assoc</span>
                <span class="nv">:inline</span> <span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">&amp;</span> <span class="nv">args</span><span class="p">]</span> <span class="o">`</span><span class="p">(</span><span class="o">.</span><span class="nv">invoke</span> <span class="nv">~hname</span> <span class="nv">~@args</span><span class="p">)))]</span>
    <span class="o">`</span><span class="p">(</span><span class="nf">do</span>
       <span class="p">(</span><span class="nf">definterface</span> <span class="nv">~iface</span>
         <span class="p">(</span><span class="nf">~</span><span class="p">(</span><span class="nb">with-meta </span><span class="ss">&#39;invoke</span> <span class="p">{</span><span class="nv">:tag</span> <span class="p">(</span><span class="nf">:tag</span> <span class="nv">name</span> <span class="nv">Object</span><span class="p">)})</span> <span class="nv">~args</span><span class="p">))</span>
       <span class="p">(</span><span class="k">def </span><span class="nv">~vname</span> <span class="nv">nil</span><span class="p">)</span> <span class="c1">; workaround for a soon-to-be-fixed bug</span>
       <span class="p">(</span><span class="k">def </span><span class="nv">~vname</span>
          <span class="p">(</span><span class="nf">reify</span>
            <span class="nv">~iface</span>
              <span class="p">(</span><span class="nf">invoke</span> <span class="p">[</span><span class="nv">this</span><span class="o">#</span> <span class="nv">~@args</span><span class="p">]</span>
                <span class="nv">~@body</span><span class="p">)</span>
            <span class="nv">clojure</span><span class="o">.</span><span class="nv">lang</span><span class="o">.</span><span class="nv">IFn</span>
              <span class="p">(</span><span class="nf">^Object</span> <span class="nv">invoke</span> <span class="p">[</span><span class="nv">this</span><span class="o">#</span> <span class="nv">~@</span><span class="p">(</span><span class="nb">map </span><span class="o">#</span><span class="p">(</span><span class="nv">vary-meta</span> <span class="nv">%</span> <span class="nv">dissoc</span> <span class="nv">:tag</span><span class="p">)</span> <span class="nv">args</span><span class="p">)]</span>
                 <span class="nv">~@body</span><span class="p">))))))</span></pre>
<p>As you can see the trick is to generate a dedicated interface and to inline calls to the defined fn to go through the specific interface rather than through IFn.</p>
<p>Let&#8217;s define a dumb numeric fn generating tons of calls: the fibonacci function! Below it comes in three flavors: hinted as int, hinted as long and plain.</p>
<pre class="highlight"><span class="p">(</span><span class="nf">defhintedfn</span> <span class="nv">^int</span> <span class="nv">hfib</span> <span class="p">[</span><span class="nv">^int</span> <span class="nv">n</span><span class="p">]</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">&gt;= </span><span class="p">(</span><span class="nb">int </span><span class="mi">1</span><span class="p">)</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nb">int </span><span class="mi">1</span><span class="p">)</span> <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">hfib</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">n</span><span class="p">))</span> <span class="p">(</span><span class="nf">hfib</span> <span class="p">(</span><span class="nb">- </span><span class="nv">n</span> <span class="p">(</span><span class="nb">int </span><span class="mi">2</span><span class="p">))))))</span>
<span class="p">(</span><span class="nf">defhintedfn</span> <span class="nv">^long</span> <span class="nv">lfib</span> <span class="p">[</span><span class="nv">^long</span> <span class="nv">n</span><span class="p">]</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">&gt;= </span><span class="p">(</span><span class="nb">long </span><span class="mi">1</span><span class="p">)</span> <span class="nv">n</span><span class="p">)</span> <span class="p">(</span><span class="nb">long </span><span class="mi">1</span><span class="p">)</span> <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">lfib</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">n</span><span class="p">))</span> <span class="p">(</span><span class="nf">lfib</span> <span class="p">(</span><span class="nb">- </span><span class="nv">n</span> <span class="p">(</span><span class="nb">long </span><span class="mi">2</span><span class="p">))))))</span>
<span class="p">(</span><span class="k">defn </span><span class="nv">fib</span> <span class="p">[</span><span class="nv">n</span><span class="p">]</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">&gt;= </span><span class="mi">1</span> <span class="nv">n</span><span class="p">)</span> <span class="mi">1</span> <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">fib</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">n</span><span class="p">))</span> <span class="p">(</span><span class="nf">fib</span> <span class="p">(</span><span class="nb">- </span><span class="nv">n</span> <span class="mi">2</span><span class="p">)))))</span></pre>
<p>And here are the timings:</p>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nf">hfib</span> <span class="mi">38</span><span class="p">))</span>
<span class="s">&quot;Elapsed time: 2016.128098 msecs&quot;</span>
<span class="mi">63245986</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nf">lfib</span> <span class="mi">38</span><span class="p">))</span>
<span class="s">&quot;Elapsed time: 2896.46198 msecs&quot;</span>
<span class="mi">63245986</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nf">fib</span> <span class="mi">38</span><span class="p">))</span>
<span class="s">&quot;Elapsed time: 4704.449867 msecs&quot;</span>
<span class="mi">63245986</span></pre>
<p>Please note that hinted fns are still regular fns:</p>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nb">map </span><span class="nv">hfib</span> <span class="p">(</span><span class="nb">range </span><span class="mi">10</span><span class="p">))</span>
<span class="p">(</span><span class="mi">1</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">5</span> <span class="mi">8</span> <span class="mi">13</span> <span class="mi">21</span> <span class="mi">34</span> <span class="mi">55</span><span class="p">)</span></pre>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/cDYEKI8vV88" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/06/04/primitive-support-for-fns/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Destructuring, records, protocols and named arguments</title>
		<link>http://clj-me.cgrand.net/2010/05/08/destructuring-records-prototypes-and-named-arguments/</link>
		<comments>http://clj-me.cgrand.net/2010/05/08/destructuring-records-prototypes-and-named-arguments/#comments</comments>
		<pubDate>Sat, 08 May 2010 10:19:31 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[optimization]]></category>
		<category><![CDATA[pondering]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=319</guid>
		<description><![CDATA[Warning: this post is full of microbenchmarks so take it with a pinch of salt. Destructuring a record Field access through keyword-lookups on records is fast: user=&#62; (defrecord Foo [a b]) user.Foo user=&#62; (let [x (Foo. 1 2)] (dotimes [_ 5] (time (dotimes [_ 1e7] (let [a (:a x) b (:b x)] [a b]))))) &#34;Elapsed [...]]]></description>
			<content:encoded><![CDATA[<p>Warning: this post is full of microbenchmarks so take it with a pinch of salt.</p>
<h3>Destructuring a record</h3>
<p>Field access through keyword-lookups on records is fast:
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">defrecord</span> <span class="nv">Foo</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">])</span>
<span class="nv">user</span><span class="o">.</span><span class="nv">Foo</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">x</span> <span class="p">(</span><span class="nf">Foo</span><span class="o">.</span> <span class="mi">1</span> <span class="mi">2</span><span class="p">)]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">5</span><span class="p">]</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">1</span><span class="nv">e7</span><span class="p">]</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">a</span> <span class="p">(</span><span class="nf">:a</span> <span class="nv">x</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">:b</span> <span class="nv">x</span><span class="p">)]</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">])))))</span>
<span class="s">&quot;Elapsed time: 114.787424 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 102.568273 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 71.150593 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 72.217418 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 70.127489 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>But as far as I know <code class="highlight"><span class="nv">destructure</span></code> still emits <code class="highlight"><span class="p">(</span><span class="nb">get </span><span class="nv">x</span> <span class="nv">:k</span><span class="p">)</span></code>, let check:
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">x</span> <span class="p">(</span><span class="nf">Foo</span><span class="o">.</span> <span class="mi">1</span> <span class="mi">2</span><span class="p">)]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">5</span><span class="p">]</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">1</span><span class="nv">e7</span><span class="p">]</span> <span class="p">(</span><span class="k">let </span><span class="p">[{</span><span class="nv">:keys</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]}</span> <span class="nv">x</span><span class="p">]</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">])))))</span>
<span class="s">&quot;Elapsed time: 968.616612 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 945.704133 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 911.290751 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 927.658125 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 916.796408 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>Actually it&#8217;s slightly slower than lookup on <i>small</i> maps:
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">x</span> <span class="p">{</span><span class="nv">:a</span> <span class="mi">1</span> <span class="nv">:b</span> <span class="mi">2</span><span class="p">}]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">5</span><span class="p">]</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">1</span><span class="nv">e7</span><span class="p">]</span> <span class="p">(</span><span class="k">let </span><span class="p">[{</span><span class="nv">:keys</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]}</span> <span class="nv">x</span><span class="p">]</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">])))))</span>
<span class="s">&quot;Elapsed time: 866.942377 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 746.273968 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 734.366239 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 729.346188 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 746.96393 msecs&quot;</span>
<span class="nv">nil</span></pre>
<h3>One patch later</h3>
<p>I <a href="http://github.com/cgrand/clojure/commit/fa130144e4466472b45db2e393ca3c3704036174">patched <code class="highlight"><span class="nv">destructure</span></code></a> to emit keyword-lookups:
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">x</span> <span class="p">(</span><span class="nf">Foo</span><span class="o">.</span> <span class="mi">1</span> <span class="mi">2</span><span class="p">)]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">5</span><span class="p">]</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">1</span><span class="nv">e7</span><span class="p">]</span> <span class="p">(</span><span class="k">let </span><span class="p">[{</span><span class="nv">:keys</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]}</span> <span class="nv">x</span><span class="p">]</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">])))))</span>
<span class="s">&quot;Elapsed time: 479.911064 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 488.895167 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 464.617431 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 480.944575 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 464.969779 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>It&#8217;s better but still slower than without destructuring. Let see what slows us:
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nb">macroexpand-1 </span><span class="o">&#39;</span><span class="p">(</span><span class="k">let </span><span class="p">[{</span><span class="nv">:keys</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]}</span> <span class="nv">x</span><span class="p">]</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]))</span>
<span class="p">(</span><span class="nf">let*</span> <span class="p">[</span><span class="nv">map__3838</span> <span class="nv">x</span> <span class="nv">map__3838</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nf">clojure</span><span class="o">.</span><span class="nv">core/seq?</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="p">(</span><span class="nf">clojure</span><span class="o">.</span><span class="nv">core/apply</span> <span class="nv">clojure</span><span class="o">.</span><span class="nv">core/hash-map</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">:b</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="nv">a</span> <span class="p">(</span><span class="nf">:a</span> <span class="nv">map__3838</span><span class="p">)]</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">])</span></pre>
<p>My bet is on the <code class="highlight"><span class="nv">if+seq?</span></code> so I remove it:
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">x</span> <span class="p">(</span><span class="nf">Foo</span><span class="o">.</span> <span class="mi">1</span> <span class="mi">2</span><span class="p">)]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">5</span><span class="p">]</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">1</span><span class="nv">e7</span><span class="p">]</span> <span class="p">(</span><span class="nf">let*</span> <span class="p">[</span><span class="nv">map__3838</span> <span class="nv">x</span> <span class="nv">map__3838</span> <span class="nv">map__3838</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">:b</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="nv">a</span> <span class="p">(</span><span class="nf">:a</span> <span class="nv">map__3838</span><span class="p">)]</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">])))))</span>
<span class="s">&quot;Elapsed time: 125.188397 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 103.041099 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 70.061558 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 70.793984 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 69.759146 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>This <code class="highlight"><span class="nv">if+seq?</span></code> allows for <a href="http://groups.google.com/group/clojure/browse_thread/thread/a032e4cba6398776/5504a45b73cc0d42">named arguments</a>. I wonder if this behaviour should be an option of map-destructuring (eg <code class="highlight"><span class="p">{</span><span class="nv">:keys</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]</span> <span class="nv">:named-args</span> <span class="nv">true</span><span class="p">}</span></code>). Anyway I had in mind that such a dispatch could be optimized with protocols.</p>
<h3>Optimizing dispatch with protocols</h3>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">defprotocol</span> <span class="nv">Seq</span> <span class="p">(</span><span class="nf">my-seq</span> <span class="p">[</span><span class="nv">this</span><span class="p">])</span> <span class="p">(</span><span class="nf">my-seq?</span> <span class="p">[</span><span class="nv">this</span><span class="p">]))</span>
<span class="nv">Seq</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">extend-protocol</span> <span class="nv">Seq</span>
<span class="nv">clojure</span><span class="o">.</span><span class="nv">lang</span><span class="o">.</span><span class="nv">ISeq</span>
<span class="p">(</span><span class="nf">my-seq</span> <span class="p">[</span><span class="nv">this</span><span class="p">]</span> <span class="p">(</span><span class="o">.</span><span class="nv">seq</span> <span class="nv">this</span><span class="p">))</span>
<span class="p">(</span><span class="nf">my-seq?</span> <span class="p">[</span><span class="nv">this</span><span class="p">]</span> <span class="nv">true</span><span class="p">)</span>
<span class="nv">Object</span>
<span class="p">(</span><span class="nf">my-seq</span> <span class="p">[</span><span class="nv">this</span><span class="p">]</span> <span class="p">(</span><span class="nf">clojure</span><span class="o">.</span><span class="nv">lang</span><span class="o">.</span><span class="nv">RT/seq</span> <span class="nv">this</span><span class="p">))</span>
<span class="p">(</span><span class="nf">my-seq?</span> <span class="p">[</span><span class="nv">this</span><span class="p">]</span> <span class="nv">false</span><span class="p">))</span>
<span class="nv">nil</span></pre>
<p>Let see how my-seq? compares to seq?
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">x</span> <span class="p">(</span><span class="nf">Foo</span><span class="o">.</span> <span class="mi">1</span> <span class="mi">2</span><span class="p">)]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">5</span><span class="p">]</span> <span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">_</span> <span class="mi">1</span><span class="nv">e7</span><span class="p">]</span> <span class="p">(</span><span class="nf">let*</span> <span class="p">[</span><span class="nv">map__3838</span> <span class="nv">x</span> <span class="nv">map__3838</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nf">my-seq?</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="p">(</span><span class="nf">clojure</span><span class="o">.</span><span class="nv">core/apply</span> <span class="nv">clojure</span><span class="o">.</span><span class="nv">core/hash-map</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="nv">b</span> <span class="p">(</span><span class="nf">:b</span> <span class="nv">map__3838</span><span class="p">)</span> <span class="nv">a</span> <span class="p">(</span><span class="nf">:a</span> <span class="nv">map__3838</span><span class="p">)]</span> <span class="p">[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">])))))</span>
<span class="s">&quot;Elapsed time: 179.282982 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 161.781526 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 154.307042 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 155.567677 msecs&quot;</span>
<span class="s">&quot;Elapsed time: 153.716604 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>Hence <code class="highlight"><span class="nv">my-seq?</span></code> is 3x faster than <code class="highlight"><span class="nv">seq?</span></code> which means that protocols are indeed speedy: yet another incredible piece of work by Rich Hickey!</p>
<p>I&#8217;m still exploring how low-level protocols fns behave in a concurrent setting, stay tuned! </p>
<p>Meanwhile don&#8217;t forget to register to the next <a href="http://conj-labs.eu/">European Clojure training session</a> taught by <a href="http://www.bestinclass.dk/">Lau</a> and me.<br />
<!--
<pre class="highlight"></pre>
<p><code class="highlight"></code> --></p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/VUChURWX6Is" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/05/08/destructuring-records-prototypes-and-named-arguments/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>European Clojure Training, Brussels, late June</title>
		<link>http://clj-me.cgrand.net/2010/04/14/european-clojure-training-brussels-late-june/</link>
		<comments>http://clj-me.cgrand.net/2010/04/14/european-clojure-training-brussels-late-june/#comments</comments>
		<pubDate>Wed, 14 Apr 2010 10:29:04 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=305</guid>
		<description><![CDATA[Following a recent tweet, I&#8217;m setting up a Clojure training session with Lau B. Jensen and we&#8217;d like to know more about our potential attendees. Please fill this short survey: Loading&#8230; (click here if you don&#8217;t see the above form.)]]></description>
			<content:encoded><![CDATA[<p>Following a <a href="http://twitter.com/cgrand/status/11473920276">recent tweet</a>, I&#8217;m setting up a Clojure training session with <a href="http://www.bestinclass.dk/index.php/blog/">Lau B. Jensen</a> and we&#8217;d like to know more about our potential attendees. Please fill this short survey:</p>
<p><iframe src="http://spreadsheets.google.com/embeddedform?formkey=dFVqa2pqZ0ZDQU5wOHFSZTgxUTlhQVE6MA" width="700" height="760" frameborder="0" marginheight="0" marginwidth="0">Loading&#8230;</iframe><br />
(<a href="http://spreadsheets.google.com/formResponse?formkey=dFVqa2pqZ0ZDQU5wOHFSZTgxUTlhQVE6MA&#038;theme=0AX42CRMsmRFbUy03NTAzM2Q4My03ODU1LTQ2NzItODI2YS1kZmU5YzdiMzZjOGQ&#038;ptok=9092854397959694515&#038;ifq">click here</a> if you don&#8217;t see the above form.)</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/N0LPFkr5GUU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/04/14/european-clojure-training-brussels-late-june/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

