<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6036367734290109040</id><updated>2011-09-05T05:16:06.422-07:00</updated><title type='text'>Full Disclojure</title><subtitle type='html'>My thoughts on the future of the design of the Clojure Language.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-8064222723852164780</id><published>2010-08-12T13:28:00.000-07:00</published><updated>2010-08-12T13:28:42.745-07:00</updated><title type='text'>Partially Implemented Protocols</title><content type='html'>Last time I discussed using a hash maps to improve code reuse with protocols.  While we produced a set of good solutions, I couldn't help but feel like we aren't quite there.  There still is a fair amount of chatter on the list about how to implement a default protocol, for example.&lt;br /&gt;&lt;br /&gt;I started experimenting with an idea I'm calling a Partially Implemented Protocol (PIP).  The idea is that you can use a PIP like you would a BaseClass in Java.  After playing around for a little bit, I settled on the following solution:  &lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/521634.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The two major components is the PIP record and extend+ macro.  Let me re-write yesterday's example with the new expand+ syntax.&lt;br /&gt;&lt;br /&gt;(defprotocol UIProtocol&lt;br /&gt;&amp;nbsp(render [])&lt;br /&gt;&amp;nbsp(action [evt])&lt;br /&gt;&amp;nbsp(button-down [evt])&lt;br /&gt;&amp;nbsp(button-up [evt]))&lt;br /&gt;&lt;br /&gt;(def BaseUIProtocol &lt;br /&gt;&amp;nbsp(pip UIProtocol&lt;br /&gt;&amp;nbsp{:action (fn [this evt] ...)&lt;br /&gt;&amp;nbsp&amp;nbsp :button-down (fn ([this evt]...)&lt;br /&gt;&amp;nbsp&amp;nbsp :button-up (fn ([this evt]...)})&lt;br /&gt;&lt;br /&gt;(extend+ TerranUIType&lt;br /&gt;&amp;nbsp BaseUIProtocol&lt;br /&gt;&amp;nbsp {:render an-existing-fn})&lt;br /&gt;&lt;br /&gt;(extend+ ProtossUIType&lt;br /&gt;&amp;nbsp BaseUIProtocol&lt;br /&gt;&amp;nbsp {:render a-different-fn})&lt;br /&gt;&lt;br /&gt;What I really like about the use of a PIP is that it allows reference to the protocol &amp; partial implementation with one record.  You can get at the internal simply by using keyword lookup, and you can also derive a PIP from another PIP like so:&lt;br /&gt;&lt;br /&gt;(def up-down-override&lt;br /&gt;&amp;nbsp :button-down button-down-2&lt;br /&gt;&amp;nbsp :button-up button-up-2})&lt;br /&gt;&lt;br /&gt;(extend+ ZergUIType&lt;br /&gt;&amp;nbsp (pip BaseUIProtocol up-down-override)&lt;br /&gt;&amp;nbsp {:render a-buggy-fn})&lt;br /&gt;&lt;br /&gt;I'm also working on versions of reify+ proxy+, etc. that all work with PIPs, assuming this idea is worth exploring.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-8064222723852164780?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/8064222723852164780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2010/08/partially-implemented-protocols.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/8064222723852164780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/8064222723852164780'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2010/08/partially-implemented-protocols.html' title='Partially Implemented Protocols'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-3925309327599805216</id><published>2010-08-11T08:03:00.000-07:00</published><updated>2010-08-11T21:56:16.822-07:00</updated><title type='text'>Protocol Implementation Awesomeness</title><content type='html'>I recently read a &lt;a href="http://programming-puzzler.blogspot.com/2010/08/racket-vs-clojure.html"&gt;post about Racket &amp; Clojure&lt;/a&gt;, and there was a question about &lt;a href="http://clojure.org/protocols" &gt;protocols&lt;/a&gt; raised.  I wanted to take the time to discuss composition of implementations with Protocols.  Of course, you probably know this term better as inheritance.&lt;br /&gt;&lt;br /&gt;Personally, my main driver for multiple inhertiance is being able to re-use different partial implementations of a class.  There are a lot a times I would want to mix &amp; match implementations of this protocol, such as UI code. Consider the following protocol&lt;br /&gt;&lt;br /&gt;(defprotocol UIProtocol&lt;br /&gt;&amp;nbsp(render [])&lt;br /&gt;&amp;nbsp(action [evt])&lt;br /&gt;&amp;nbsp(button-down [evt])&lt;br /&gt;&amp;nbsp(button-up [evt]))&lt;br /&gt;&lt;br /&gt;Now, we can extend the protocol as such&lt;br /&gt;&lt;br /&gt;(extend UIType&lt;br /&gt;&amp;nbsp UIProtocol&lt;br /&gt;&amp;nbsp {:render an-existing-fn&lt;br /&gt;&amp;nbsp&amp;nbsp :action (fn [this evt] ...)&lt;br /&gt;&amp;nbsp&amp;nbsp :button-down (fn ([this evt]...)&lt;br /&gt;&amp;nbsp&amp;nbsp :button-up (fn ([this evt]...)})&lt;br /&gt;&lt;br /&gt;So far so good.  However, suppose we have another UI type we want to define&lt;br /&gt;&lt;br /&gt;(extend AnotherUIType&lt;br /&gt;&amp;nbsp UIProtocol&lt;br /&gt;&amp;nbsp {:render a-different-fn&lt;br /&gt;&amp;nbsp&amp;nbsp :action (fn [this evt] ...)&lt;br /&gt;&amp;nbsp&amp;nbsp :button-down (fn ([this evt]...)&lt;br /&gt;&amp;nbsp&amp;nbsp :button-up (fn ([this evt]...)})&lt;br /&gt;&lt;br /&gt;The only thing that is different between the implementations is the rendering logic (similar behavior, different skin?  What sort of &lt;a href="http://starcraft2.com"&gt;problem domain&lt;/a&gt; has that?).  Our implementation works, but it's repetitive.  &lt;br /&gt;&lt;br /&gt;In order to clean it up, we'll need to use a defining feature of Lisp: code is data.  Remember we are building a data structure to define our type.  As such, we can use every DRY trick we know.  In our specific example, we take advantage of the fact that the extend macro is expecting a hash-map, and it doesn't care how it gets there.  So, here's a new take on the code.&lt;br /&gt;&lt;br /&gt;(def base-impl&lt;br /&gt;&amp;nbsp {:action (fn [this evt] ...)&lt;br /&gt;&amp;nbsp&amp;nbsp :button-down (fn ([this evt]...)&lt;br /&gt;&amp;nbsp&amp;nbsp :button-up (fn ([this evt]...)})&lt;br /&gt;&lt;br /&gt;(extend TerranUIType&lt;br /&gt;&amp;nbsp UIProtocol&lt;br /&gt;&amp;nbsp (merge base-impl {:render an-existing-fn}))&lt;br /&gt;&lt;br /&gt;(extend ProtossUIType&lt;br /&gt;&amp;nbsp UIProtocol&lt;br /&gt;&amp;nbsp (merge base-impl {:render a-different-fn})&lt;br /&gt;&lt;br /&gt;BAM! I've overridden render with my specific implementation.  We just simulated the abstract base class pattern.  Now, let's see how flexible this really lets us be.&lt;br /&gt;&lt;br /&gt;(def up-down-override&lt;br /&gt;&amp;nbsp :button-down button-down-2&lt;br /&gt;&amp;nbsp&amp;nbsp :button-up button-up-2})&lt;br /&gt;&lt;br /&gt;(extend ZergUIType&lt;br /&gt;&amp;nbsp UIProtocol&lt;br /&gt;&amp;nbsp (merge base-impl up-down-override {:render a-buggy-fn});-p&lt;br /&gt;&lt;br /&gt;What this let me do is define my own inheritance rules a la carte.  No implicit order of operations, no compiler limitations, no confusing precedence rules.  If you can figure out the map merging, you can do it.  Period.  That's why I think Clojure Protocols are so awesome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-3925309327599805216?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/3925309327599805216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2010/08/thoughts-on-protocols.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/3925309327599805216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/3925309327599805216'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2010/08/thoughts-on-protocols.html' title='Protocol Implementation Awesomeness'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-1736554714766954629</id><published>2010-04-08T21:06:00.000-07:00</published><updated>2010-04-08T21:06:52.790-07:00</updated><title type='text'>Steve Jobs just ruined the iPhone for Clojure</title><content type='html'>Recently Apple released new terms of service with their &amp;nbsp;iPhone OS. &amp;nbsp;By now most of you have seen the following section. &amp;nbsp;I've copied this from Daring Fireball&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, 'Bitstream Vera Sans', sans-serif; font-size: 11px; line-height: 19px;"&gt;3.3.1 — Applications may only use Documented APIs in the manner prescribed by Apple and must not use or call any private APIs. Applications must be originally written in Objective-C, C, C++, or JavaScript as executed by the iPhone OS WebKit engine, and only code written in C, C++, and Objective-C may compile and directly link against the Documented APIs (e.g., Applications that link to Documented APIs through an intermediary translation or compatibility layer or tool are prohibited).&lt;/span&gt;&lt;/blockquote&gt;I'm pissed off. &amp;nbsp;I believe the hype, and there's a lot of HCI experiments I'd like to do with the iPhone &amp;amp; iPad. &amp;nbsp;There's a ton of opportunities &amp;amp; ideas, waiting to be discovered. &amp;nbsp;Being able to do these experiments in Clojure would be some much fun, that it's worth the $500 investment.&lt;br /&gt;&lt;br /&gt;If I'm reading the TOS, we can't have a version of Clojure on this platform. &amp;nbsp;Any ideas I have - no, we have - now can't be shared with the world.&lt;br /&gt;&lt;br /&gt;This is NOT thinking differently Apple.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-1736554714766954629?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/1736554714766954629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2010/04/steve-jobs-just-ruined-iphone-for.html#comment-form' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/1736554714766954629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/1736554714766954629'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2010/04/steve-jobs-just-ruined-iphone-for.html' title='Steve Jobs just ruined the iPhone for Clojure'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-4800574056044083621</id><published>2010-04-06T10:02:00.000-07:00</published><updated>2010-04-06T10:02:04.746-07:00</updated><title type='text'>New Getting started page</title><content type='html'>Clojure's getting started information has moved.&amp;nbsp; You can check it out here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.assembla.com/wiki/show/clojure/Getting_Started%20"&gt;Clojure Getting Started&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-4800574056044083621?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/4800574056044083621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2010/04/new-getting-started-page.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/4800574056044083621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/4800574056044083621'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2010/04/new-getting-started-page.html' title='New Getting started page'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-7479855339492682895</id><published>2010-03-26T08:12:00.000-07:00</published><updated>2010-03-26T08:14:52.718-07:00</updated><title type='text'>Too much Clojure when...</title><content type='html'>I can no long spell the following words properly.  This is really annoying when talking to people outside of this community :)&lt;br /&gt;&lt;ul style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;li&gt;Closure/Clojure&lt;/li&gt;&lt;li&gt;Definitely/Defnitely&lt;/li&gt;&lt;li&gt;Disclosure/Disclojure (self inflicted)&lt;/li&gt;&lt;li&gt;Composure/Compojure &lt;/li&gt;&lt;/ul&gt;Thanks for nothing Rich :-p&lt;br /&gt;&lt;br /&gt;What're your experiences?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-7479855339492682895?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/7479855339492682895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2010/03/too-much-clojure-when.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/7479855339492682895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/7479855339492682895'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2010/03/too-much-clojure-when.html' title='Too much Clojure when...'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-2671046683959100952</id><published>2010-02-18T07:34:00.000-08:00</published><updated>2010-02-18T07:34:12.795-08:00</updated><title type='text'>Thoughts on namespace management</title><content type='html'>Konrad Hinsen recently posted some ideas for handling namespaces&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.google.com/url?sa=D&amp;amp;q=http://onclojure.com/2010/02/17/managing-namespaces&amp;amp;usg=AFQjCNGarHZVgwtFN5M1hkaqmL5aui6dpA" rel="nofollow" target="_blank"&gt;http://onclojure.com/2010/02/17/managing-namespaces&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are a lot of good ideas in there, and right now I'd like to talk specifically about the proposed :like &amp;amp; :clone clauses.&amp;nbsp; I have a bit of a different approach.&lt;br /&gt;&lt;br /&gt;Supposed we add a new project file, namespace_config.clj.&amp;nbsp; It would be a basic rules engine for configuring namespaces.&amp;nbsp; I'm thinking there would be a macro, extend-ns, that is roughly defined as follows.  The exact implementation needs work.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/307738.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;This lets us set up a series of predicates &amp; resulting actions that would be applied to each ns in the project.  Everything would be done in one central location, so (hopefully) that would cut down on maintenance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-2671046683959100952?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/2671046683959100952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2010/02/thoughts-on-namespace-management.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/2671046683959100952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/2671046683959100952'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2010/02/thoughts-on-namespace-management.html' title='Thoughts on namespace management'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-1494245643706986414</id><published>2010-01-24T12:16:00.000-08:00</published><updated>2010-01-24T12:16:20.633-08:00</updated><title type='text'>Code Kata:  A data sifter</title><content type='html'>Here's a problem inspired by a scheme example I discovered another day.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://programming-musings.org/2006/02/07/scheme-code-kata/"&gt;http://programming-musings.org/2006/02/07/scheme-code-kata/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Write a data sifter, sift, that partitions a string into a list of lists. &amp;nbsp;Start with the case of using letters as a delimiter, and numbers as data. &amp;nbsp;There can be any number of repetitions of numbers &amp;amp; letters.&lt;br /&gt;&lt;br /&gt;user=&amp;gt;(sift "a1b2cd34")&lt;br /&gt;(("a" ("1")) ("b" ("2")) ("c" ()) ("d" ("3" "4")))&lt;br /&gt;&lt;br /&gt;Next, add the ability to your sift function to accept a list as input, as well as a string.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;user=&amp;gt;(sift ("a" "1" "b" "2" "c" "d" "3" "4"))&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;(("a" ("1")) ("b" ("2")) ("c" ()) ("d" ("3" "4")))&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;After that, add the ability to take a vector/array as an input&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;user=&amp;gt;(sift ["a" "1" "b" "2" "c" "d" "3" "4"])&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;(("a" ("1")) ("b" ("2")) ("c" ()) ("d" ("3" "4")))&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Finally, let your sift accept a collection of any object, and an arbitrary predicate. &amp;nbsp;If the predicate is true, the object is a delimiter (e.g. a String). &amp;nbsp;If the predicate is false, the object is data (e.g. a Number).&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;user=&amp;gt;(sift string? ["a" 1 "b" 2 "c" "d" 3 4])&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;(("a" (1)) ("b" (2)) ("c" ()) ("d" (3 4)))&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;I'll be posting my solution in about a week.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-1494245643706986414?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/1494245643706986414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2010/01/code-kata-data-sifter.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/1494245643706986414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/1494245643706986414'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2010/01/code-kata-data-sifter.html' title='Code Kata:  A data sifter'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-5682534088993636518</id><published>2010-01-03T20:21:00.000-08:00</published><updated>2010-01-03T20:21:50.471-08:00</updated><title type='text'>1.2 fn Proposal: same &amp; multisame</title><content type='html'>Hello Clojure Developers,&lt;br /&gt;Writing software frequently follows the same process.  Observing &amp;amp; understanding the processes and coming up with effective solutions is the task of library design.  An API is judged by how well it fits into the process.&lt;br /&gt;&lt;br /&gt;Application design is a slightly different process.  For the purposes of this proposal, it involves three oversimplified steps.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Convert problem data to a form the API can understand.&lt;/li&gt;&lt;li&gt;Use the API to come up with a solved version of the problem.&lt;/li&gt;&lt;li&gt;Convert the API produced solution back to the problem domain solution.&lt;/li&gt;&lt;/ol&gt;One of features we all love about Clojure is the sequence abstraction.  For many problems, it drastically reduces the time required to convert the specific problem to a form that the API understands.  Once a problem is transformed to operating on a string, map, vector or set the sequence functions can take it from there.  This brings steps 1 &amp;amp; 2 very close to each other.&lt;br /&gt;&lt;br /&gt;However, there currently is not much work done to bring steps 2 &amp;amp; 3 closer to each other.  This is evidenced by the fact that there are specialized namespaces in contrib for handling strings (str-utils2), functor application (generic.functor), and I was in the middle of proposing additions to the map-utils library.&lt;br /&gt;&lt;br /&gt;All this code duplication started to smell.  Here we all are writing specialized routines to AVOID using the sequence functions in our code.  This is not right.&lt;br /&gt;&lt;br /&gt;I have a proposal to eliminate this smell.  I've written a higher order function called same.  Here's the doc:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span style="color: #444444;"&gt;lib.sfd.same/same&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span style="color: #444444;"&gt;([index? seq-fn &amp;amp; args])&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span style="color: #444444;"&gt;"same is a mutlimethod that is designed to "undo" seq.  It expects a seq-fn that returns a normal seq, and the appropraite args.  By default it converts the resulting seq into the same type as the last argument.  An optional leading integer, index, can be provided to specify the index of the argument that should be used to convert the seq.  If it is a sorted seq, the comparator is preserved.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span style="color: #444444;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span style="color: #444444;"&gt;This operation is fundamentally eager, unless a lazy seq is detected.  In this case no conversion is attempted, and laziness is preserved."&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Please take a moment to review a fairly robust list of examples now:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/francoisdevlin/devlinsf-clojure-utils/blob/master/test/lib/sfd/same_test.clj"&gt;http://github.com/francoisdevlin/devlinsf-clojure-utils/blob/master/test/lib/sfd/same_test.clj&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Afterwards, you can peruse the code here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/francoisdevlin/devlinsf-clojure-utils/blob/master/src/lib/sfd/same.clj"&gt;http://github.com/francoisdevlin/devlinsf-clojure-utils/blob/master/src/lib/sfd/same.clj&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This one function will provide the same functionality as the proposed map-utils, some of c.c.str-utils2, c.c.generic.functor, or any desired set &amp;amp; vector utils.  It's based on a multimethod, so you are a simple defmethod addition away from keyword-utils or symbol-utils (assuming you'd want to treat them like strings).&lt;br /&gt;&lt;br /&gt;I've also designed a method, multi-same, for functions that take a sequence in and split it into several sequences.  Here's a quick example, as the uses for multi-same are still being developed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span style="color: #444444;"&gt;user=&amp;gt;(multi-same partition 2 "abcd")&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span style="color: #444444;"&gt;("ab" "cd")&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One thing that I find VERY fascinating is the areas where same &amp;amp; multi-same do NOT allow str-utils2 to be replaced out of the box.  Some of these can easily be explained.  str-utils2/trim is a very string specific piece of code.  However, others cannot easily be explained.  Why is it that there is no way to split a sequence similar to a regular expression?&lt;br /&gt;&lt;br /&gt;I think these areas where string processing is easier represent places we need to improve our sequence library.  I've included some new functions in lib.sfd.seq-utils, and I would ask this group to consider adding them to c.c.seq-utils or core.&lt;br /&gt;&lt;br /&gt;There also isn't a parser that works with predicates &amp;amp; sequences in core yet.  I suspect fn-parse may be a start.  I'd appreciate help from anyone that is good with parsers/monads.&lt;br /&gt;&lt;br /&gt;So, here's a chance to simultaneously reduce the amount of code in contrib and add lots of functionality to Clojure.  In summary, here's what I'm proposing&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add same to core&lt;/li&gt;&lt;li&gt;Add multi-same to core&lt;/li&gt;&lt;li&gt;Add new sequence fns to contrib or core&lt;/li&gt;&lt;li&gt;Add a new sequence parser to contrib or core&lt;/li&gt;&lt;/ol&gt;There is one more plea I would like to add on a personal note.  People are always detracting from Lisp, asking us to provide examples of how it is more productive than other languages.  I believe this is an opportunity to build something that replaces several libraries with one function.  It would be an example of how Lisp *eliminates the need* for writing code, very concisely.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPDATE 1/3&lt;/b&gt;: &amp;nbsp;I re-wrote same &amp;amp; multi-same to work with a protocol, per Stuart Sierra's suggestion.&lt;br /&gt;&lt;br /&gt;I look forward to the discussion,&lt;br /&gt;Sean&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-5682534088993636518?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/5682534088993636518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2010/01/12-fn-proposal-same-multisame.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/5682534088993636518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/5682534088993636518'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2010/01/12-fn-proposal-same-multisame.html' title='1.2 fn Proposal: same &amp; multisame'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-7796938801366960305</id><published>2009-12-25T20:59:00.001-08:00</published><updated>2009-12-26T15:57:35.377-08:00</updated><title type='text'>How to write a Clojure reader macro, part 2</title><content type='html'>This is a follow up to my earlier post about writing a reader macro.  Here's the disclaimer again.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-weight:bold;color:red;"&gt;&lt;br /&gt;&lt;h2&gt;DISCLAIMER&lt;/h2&gt;&lt;br /&gt;I Completely agree with Rich's decision to NOT support reader macros.  In an activity as simple as writing this post, I found many, many places to make a mistake the hard way.   This is an extremely difficult activity to get right, and the end result is something that is not quite the same as normal Clojure.  Use the following information at your own risk.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Okay, now that that's been said, let's get on with it.  We're going to write a multi-character delimited reader macro this time.  Since I'm a point free junkie, we're going to use partial for our example.&lt;br /&gt;&lt;br /&gt;Here's what the final use case is going to be&lt;br /&gt;&lt;br /&gt;user=&gt;#[+ 1]&lt;br /&gt;#&amp;lt core$partial ...&amp;gt&lt;br /&gt;&lt;br /&gt;Let's start modifying LispReader.java again.  The first thing we're going to do is insert a static symbol&lt;br /&gt;&lt;br /&gt;//Inserted at line 40 &lt;br /&gt;static Symbol INTERPOLATE_S = Symbol.create("clojure.core", "partial");&lt;br /&gt;&lt;br /&gt;Now, Let's take a look around line 84.  You'll see the following entry in the array&lt;br /&gt;&lt;br /&gt;macros['#'] = new DispatchReader();&lt;br /&gt;&lt;br /&gt;The # character is bound to a DispatchReader.  This is the object closure uses to implement multiple character reader macros (ever notice that they all start with #?).  You'll also notice that there is a dispatchMacros array with several entires in it.  Add the following entry&lt;br /&gt;&lt;br /&gt;dispatchMacros['['] = new PartialReader();&lt;br /&gt;&lt;br /&gt;We also need to define the PartialReader class.  It is based on the VectorReader class, which can be found around line 994.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/263842.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The heavy lifting is done by the readDelimitedList method.  Note that the closing delimiter needs to be provided, and the recursive flag should be set to true.  It returns an IPersistentList object.  The only thing that needs to be done is to prepend a partial to the list.  That is why the cons method is used to add a partial symbol (you still need classic macro-fu).&lt;br /&gt;&lt;br /&gt;We've added everything we need to add to LispReader.java.  All that's left to do is recompile clojure.jar and test the results&lt;br /&gt;&lt;br /&gt;user=&gt;(map #[+ 1] [1 2 3])&lt;br /&gt;(2 3 4)&lt;br /&gt;&lt;br /&gt;Of course, now that I think about it, comment might be a better symbol to use than partial...&lt;br /&gt;&lt;br /&gt;That's how you add a delimited reader macro.  Next time we'll look at creating a new dispatch character, and properly escaping everything.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-7796938801366960305?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/7796938801366960305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2009/12/how-to-write-clojure-reader-macro-part.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/7796938801366960305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/7796938801366960305'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2009/12/how-to-write-clojure-reader-macro-part.html' title='How to write a Clojure reader macro, part 2'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-5115896567749731421</id><published>2009-12-17T16:34:00.000-08:00</published><updated>2010-01-03T19:31:42.124-08:00</updated><title type='text'>Proposal for 1.2 : New Seq Utilities</title><content type='html'>&lt;div&gt;Time to brainstorm everyone!&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've been trying to come up with new sequence functions.  Of course, there's nothing really new about these at all.  They just aren't in core or c.c.seq-utils.  Do any of these belong in contrib or core?&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;alternate&lt;/b&gt; [pred coll]&lt;br /&gt;&lt;/div&gt;&lt;div&gt;returns an alternating collection.  Similar to a regex partition.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;split&lt;/b&gt; [pred coll]&lt;br /&gt;&lt;/div&gt;&lt;div&gt;returns a collection of collection, split by matching the predicate.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;take-last&lt;/b&gt; [n coll]&lt;br /&gt;&lt;div&gt;&lt;div&gt;The mirror of drop-last&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;take-until&lt;/b&gt; [pred coll]&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Returns a lazy sequence of successive items from coll while (pred item) returns false. pred must be free of side-effects.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;drop-until&lt;/b&gt; [pred coll]&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Returns a lazy sequence of the items in coll starting from the first item for which (pred item) returns true.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;rotate&lt;/b&gt; [n coll]&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Take a collection and left rotates it n steps.  If n is negative, the collection is rotated right. Executes in O(n) time.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;rotate-while&lt;/b&gt; [pred coll]&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Rotates a collection left while (pred item) is true.  Will return a unrotated sequence if (pred item) is never true. Executes in O(n) time.&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;rotate-until&lt;/b&gt; [pred coll]&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Rotates a collection left while (pred item) is nil.  Will return a unrotated sequence if (pred item) is always true. Executes in O(n) time.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, I define all of these functions and more here:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://github.com/francoisdevlin/devlinsf-clojure-utils/blob/master/src/lib/sfd/seq_utils.clj"&gt;http://github.com/francoisdevlin/devlinsf-clojure-utils/blob/master/src/lib/sfd/seq_utils.clj&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://github.com/francoisdevlin/devlinsf-clojure-utils/blob/master/src/lib/sfd/patterns.clj"&gt;http://github.com/francoisdevlin/devlinsf-clojure-utils/blob/master/src/lib/sfd/patterns.clj&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Do others have ideas for missing seq utilities?&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-5115896567749731421?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/5115896567749731421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2009/12/new-seq-utilities.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/5115896567749731421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/5115896567749731421'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2009/12/new-seq-utilities.html' title='Proposal for 1.2 : New Seq Utilities'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-2488094774270194368</id><published>2009-12-15T19:51:00.000-08:00</published><updated>2009-12-25T20:59:05.301-08:00</updated><title type='text'>How to write a Clojure reader macro</title><content type='html'>This is an article on how to write a basic reader macro in Clojure.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-weight:bold;color:red;"&gt;&lt;br /&gt;&lt;h2&gt;DISCLAIMER&lt;/h2&gt;&lt;br /&gt;I Completely agree with Rich's decision to NOT support reader macros.  In an activity as simple as writing this post, I found many, many places to make a mistake the hard way.   This is an extremely difficult activity to get right, and the end result is something that is not quite the same as normal Clojure.  Use the following information at your own risk.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The first thing to identify is a behavior that you would like to have a reader macro for.  For our example, I am going to use a modified form of Chas Emerick's amazing string interpolation macro.  You can find his original article &lt;a href="http://muckandbrass.com/web/display/~cemerick/2009/12/04/String+Interpolation+in+Clojure"&gt;here&lt;/a&gt;.  I took a modified version of his code, and placed it in core.clj (Be sure to create a new git branch).  The code I used is below&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/257549.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Now that the desired functionality is in core, it is time to modify the reader.  In this case we need to modify the file LispReader.java.  I defined a static variable INTERPOLATE_S, and I am going to assign it the "|" reader macro.&lt;br /&gt;&lt;br /&gt;//Inserted at line 40&lt;br /&gt;static Symbol INTERPOLATE_S = Symbol.create("clojure.core", "interpolate-s");&lt;br /&gt;&lt;br /&gt;Now, in order for this to be found we need to make an entry in the macros array.  This can be done like so:&lt;br /&gt;&lt;br /&gt;//Inserted at line 86&lt;br /&gt;macros['|'] = new WrappingReader(INTERPOLATE_S);&lt;br /&gt;&lt;br /&gt;The WrappingReader class takes a Symbol object, and wraps it around the next form that is read.  Recall how the following form&lt;br /&gt;&lt;br /&gt;@a-ref&lt;br /&gt;&lt;br /&gt;is expanded to (deref a-ref).  In our case&lt;br /&gt;&lt;br /&gt;|"A string ~(+ 2 2)"&lt;br /&gt;&lt;br /&gt;will be expanded to&lt;br /&gt;&lt;br /&gt;(interpolate-s "A string ~(+ 2 2)")&lt;br /&gt;&lt;br /&gt;Let's rebuild clojure.jar and try this out at a REPL.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/257582.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;As you can see this works just like Chas' macro.  There are still a few things that need to be covered, such as:&lt;br /&gt;&lt;br /&gt;* How to create a multiple character reader macro&lt;br /&gt;* How to create a delimited reader macro&lt;br /&gt;&lt;br /&gt;These will be topics for another day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-2488094774270194368?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/2488094774270194368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2009/12/how-to-write-clojure-reader-macro.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/2488094774270194368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/2488094774270194368'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2009/12/how-to-write-clojure-reader-macro.html' title='How to write a Clojure reader macro'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-948559855992865331</id><published>2009-12-08T22:10:00.000-08:00</published><updated>2009-12-10T19:21:14.819-08:00</updated><title type='text'>uses for take/drop-while</title><content type='html'>I've found a use for take-while &amp; drop-while in a map.&lt;br /&gt;&lt;br /&gt;To start let's define the following&lt;br /&gt;&lt;br /&gt;user=&gt;(defn sort-map [m] (apply sorted-map (apply concat m)))&lt;br /&gt;&lt;br /&gt;That's right.  A function to cast hash-map to tree-maps.&lt;br /&gt;&lt;br /&gt;user=&gt;(sort-map {3 :a 1 :c 2 :b})&lt;br /&gt;{1 :c, 2 :b, 3 :a}&lt;br /&gt;&lt;br /&gt;Why would I do that?  Because I now have a way of making subsets based on the keys.&lt;br /&gt;&lt;br /&gt;user=&gt;(keys-pred take-while #(&lt; 2 %) (sort-map {3 :a 1 :c 2 :b}))&lt;br /&gt;{1 :c}&lt;br /&gt;&lt;br /&gt;user=&gt;(keys-pred drop-while #(&lt; 2 %) (sort-map {3 :a 1 :c 2 :b}))&lt;br /&gt;{2 :b, 3 :a}&lt;br /&gt;&lt;br /&gt;So, when would this have an application?&lt;br /&gt;&lt;br /&gt;&lt;a href="http://xkcd.com/287/"&gt;&lt;br /&gt;&lt;img src="http://imgs.xkcd.com/comics/np_complete.png" width="450px"&gt;&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;Let's define the following map&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/253922.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;And there you go, a use for take/drop while with maps :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-948559855992865331?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/948559855992865331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2009/12/uses-for-takedrop-while.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/948559855992865331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/948559855992865331'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2009/12/uses-for-takedrop-while.html' title='uses for take/drop-while'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-1702234888760860849</id><published>2009-11-23T08:02:00.000-08:00</published><updated>2009-11-23T11:26:47.336-08:00</updated><title type='text'>Feedback for a visitor closure generator</title><content type='html'>Multimethods are a great abstraction in Clojure.  They are great for adapting a wide variety of inputs to a function.  However, I often need to decouple the adaptation of data from the function that operates on the adapted data.  Also, after the work is complete, I need to adapt the data back to the original format.&lt;br /&gt;&lt;br /&gt;As such, I've found the need to create visitor closures in my code.  Along the way I came up with a helper function to generate visitor closures.  I'd like feedback on the visitor generator.&lt;br /&gt;&lt;br /&gt;* Getting Motivated: String functions *&lt;br /&gt;&lt;br /&gt;I write the following code a lot to deal with keywords &amp; symbols:&lt;br /&gt;&lt;br /&gt;(keyword (some-str-fn (name a-keyword) str-fn-args))&lt;br /&gt;(symbol  (some-str-fn (name a-symbol ) str-fn-args))&lt;br /&gt;&lt;br /&gt;Each of these can be abstracted out as&lt;br /&gt;(defn visit-keyword&lt;br /&gt; [str-fn a-keyword &amp; args]&lt;br /&gt;    (keyword &lt;br /&gt;      (apply str-fn (name a-keyword) args)))&lt;br /&gt;&lt;br /&gt;(defn visit-symbol&lt;br /&gt; [str-fn a-symbol &amp; args]&lt;br /&gt;    (symbol &lt;br /&gt;      (apply str-fn (name a-symbol ) args)))&lt;br /&gt;&lt;br /&gt;So, the code is now called as follows&lt;br /&gt;&lt;br /&gt;(visit-keyword str-fn a-keyword args)&lt;br /&gt;(visit-symbol  str-fn a-symbol args)&lt;br /&gt;&lt;br /&gt;This is one possible implementation of a visitor patter for symbols, keywords &amp; strings.&lt;br /&gt;&lt;br /&gt;* More Problems: Map Functions *&lt;br /&gt;&lt;br /&gt;It's common to filter on values or keys when working with maps.  I've written a lot of code like this:&lt;br /&gt;&lt;br /&gt;;keys&lt;br /&gt;(into {} (some-pred-fn (comp a-pred key) map-fn-args))&lt;br /&gt;;values&lt;br /&gt;(into {} (some-pred-fn (comp a-pred val) map-fn-args))&lt;br /&gt;&lt;br /&gt;A first approach would be to write specific helper function for each case.  However, this can be turned into a visitor as well.&lt;br /&gt;&lt;br /&gt;(defn visitor-keys-pred&lt;br /&gt;  [pred-fn pred-arg &amp; args]&lt;br /&gt;    (into {} &lt;br /&gt;      (apply pred-fn (#(comp % key) pred-arg) &lt;br /&gt;        args)))&lt;br /&gt;&lt;br /&gt;(defn visitor-vals-pred&lt;br /&gt;  [pred-fn pred-arg &amp; args]&lt;br /&gt;    (into {} &lt;br /&gt;      (apply pred-fn (#(comp % val) pred-arg) &lt;br /&gt;        args)))&lt;br /&gt;&lt;br /&gt;The definition looks a little funky, but we'll see why in a minute.  For now the functions can be called as follows:&lt;br /&gt;&lt;br /&gt;(visitor-keys-pred pred-fn pred-arg args)&lt;br /&gt;(visitor-vals-pred pred-fn pred-arg args)&lt;br /&gt;&lt;br /&gt;* Putting it together:  Visitor Closures *&lt;br /&gt;&lt;br /&gt;As you can see, a pattern is starting to develop.  Each visitor function has a similar signature:&lt;br /&gt;&lt;br /&gt;[f first-arg &amp; rest-args]&lt;br /&gt;&lt;br /&gt;This obviously becomes&lt;br /&gt;&lt;br /&gt;[f &amp; args]&lt;br /&gt;&lt;br /&gt;Each visitor follows a similar pattern, too.&lt;br /&gt;1.  Apply a visit-fn to get to a common base type&lt;br /&gt;2.  Do work on the base type&lt;br /&gt;3.  Apply a return-fn to get back to the original type.&lt;br /&gt;&lt;br /&gt;We can turn this description into a closure generating function:&lt;br /&gt;&lt;br /&gt;(defn visitor&lt;br /&gt;  "Used to implement visitor patterns. (first (args)) is modified by the visitor function, and the result is wrapped in a return-fn call."&lt;br /&gt;  [visit-fn return-fn]&lt;br /&gt;  (fn [f &amp; args]&lt;br /&gt;    (return-fn&lt;br /&gt;     (apply f &lt;br /&gt;       (visit-fn (first args))&lt;br /&gt;       (rest args)))))&lt;br /&gt;&lt;br /&gt;We now have a new way to define previous visitor functions.  Here's what they look like using this new helper function:&lt;br /&gt;&lt;br /&gt;(def visit-keyword (visitor name keyword))&lt;br /&gt;(def visit-symbol  (visitor name symbol ))&lt;br /&gt;&lt;br /&gt;;Works w/ predicate functions&lt;br /&gt;(def visit-keys-pred (visitor #(comp % key) (partial into {}))&lt;br /&gt;(def visit-vals-pred (visitor #(comp % val) (partial into {}))&lt;br /&gt;&lt;br /&gt;As you can see, the only thing we described is the visit-fn and return-fn.  The rest of the behavior is defined by the visitor pattern itself.&lt;br /&gt;&lt;br /&gt;* Second form *&lt;br /&gt;&lt;br /&gt;The one catch is that visitor assumes that the dispatched data is the first argument to f.  Sometimes it is the last argument to f, as in take &amp; drop.  It is easy enough to define visitor* that works on the last argument of a function.  The definition is in the link.&lt;br /&gt;&lt;br /&gt;http://gist.github.com/241144&lt;br /&gt;&lt;br /&gt;* Back to Multimethods *&lt;br /&gt;&lt;br /&gt;The power of the individual closures can be amplified when wrapped in a multimethod.  Consider our String/Symbol/Keyword group.&lt;br /&gt;&lt;br /&gt;(defmulti visit-string (fn [&amp; args] (second args))&lt;br /&gt;&lt;br /&gt;(defmethod visit-string clojure.lang.Symbol&lt;br /&gt; [f &amp; args]&lt;br /&gt; (apply visit-symbol f args))&lt;br /&gt;&lt;br /&gt;(defmethod visit-string clojure.lang.Keyword&lt;br /&gt; [f &amp; args]&lt;br /&gt; (apply visit-keyword f args))&lt;br /&gt;&lt;br /&gt;(defmethod visit-string :default&lt;br /&gt; [f &amp; args]&lt;br /&gt; (apply f args))&lt;br /&gt;&lt;br /&gt;We now have a visit-string function that can truly visit anything.  Our function calls above become:&lt;br /&gt;&lt;br /&gt;(visit-string str-fn a-keyword args)&lt;br /&gt;(visit-string str-fn a-symbol  args)&lt;br /&gt;&lt;br /&gt;* Closing questions *&lt;br /&gt;&lt;br /&gt;So now that you've how &amp; why this works, I've got some questions for the group:&lt;br /&gt;&lt;br /&gt;* Did I accidentally duplicate functionality in core?&lt;br /&gt;* How can this be more flexible?&lt;br /&gt;* What maintenance problems are there that I don't see?&lt;br /&gt;* Will speed be an issue?&lt;br /&gt;* Is the signature of visitor sensible?  Is the signature of the generated function sensible?  How could it be better?&lt;br /&gt;&lt;br /&gt;Thanks in advance,&lt;br /&gt;Sean&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-1702234888760860849?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/1702234888760860849/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2009/11/rfc-feedback-for-visitor-closure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/1702234888760860849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/1702234888760860849'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2009/11/rfc-feedback-for-visitor-closure.html' title='Feedback for a visitor closure generator'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-4229938224311976391</id><published>2009-09-30T09:18:00.000-07:00</published><updated>2009-09-30T09:25:33.069-07:00</updated><title type='text'>Short circuiting reductions</title><content type='html'>Sometimes reduce needs to short circuit&lt;br /&gt;&lt;br /&gt;&lt;div class="code-block"&gt;&lt;br /&gt;(defn reducer&lt;br /&gt;&lt;span class="doc-string"&gt;&amp;nbsp "Returns a reduction closure the terminates when pred is false.  Applies f to the last value that returns true. f defaults to identity if not provided.  Behaves like reduce if pred is always true."&lt;/span&gt;&lt;br /&gt;&amp;nbsp ([pred] (reducer pred identity))&lt;br /&gt;&amp;nbsp ([pred f] (do-stuff:TBD))&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-4229938224311976391?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/4229938224311976391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2009/09/short-circuiting-reductions.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/4229938224311976391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/4229938224311976391'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2009/09/short-circuiting-reductions.html' title='Short circuiting reductions'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6036367734290109040.post-8746777189727874762</id><published>2009-09-23T11:31:00.000-07:00</published><updated>2009-09-30T09:41:39.541-07:00</updated><title type='text'>Uses for juxt</title><content type='html'>The juxtaposition operator can be used in parsing text.  &lt;br /&gt;&lt;br /&gt;Suppose we have the following text to process:&lt;br /&gt;&lt;br /&gt;&lt;div class="code-block"&gt;INSERT TEXT HERRE&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Consider the following function which gets information from the clipboard&lt;br /&gt;&lt;br /&gt;&lt;div class="code-block"&gt;(defn bom-parser&lt;br /&gt;&amp;nbsp [part-num] &lt;br /&gt;&amp;nbsp &amp;nbsp (map (&amp;amp; &lt;br /&gt;&lt;span class="stressed-line"&gt;&amp;nbsp &amp;nbsp &amp;nbsp (juxt last second (constantly part-num))&lt;/span&gt;&lt;br /&gt;&amp;nbsp &amp;nbsp &amp;nbsp (p split #"\s+")&lt;br /&gt;&amp;nbsp &amp;nbsp &amp;nbsp trim)&lt;br /&gt;&amp;nbsp &amp;nbsp &amp;nbsp ((&amp;amp; split-lines&lt;br /&gt;&amp;nbsp &amp;nbsp &amp;nbsp &amp;nbsp (p gsub #"\"" "")&lt;br /&gt;&amp;nbsp &amp;nbsp &amp;nbsp &amp;nbsp (p gsub #"NOT SHOWN" ""))&lt;br /&gt;&amp;nbsp &amp;nbsp &amp;nbsp  (get-clip))))&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In the mapping operation you can see a call to juxt.  This helps turn a block of text into a list of vectors.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6036367734290109040-8746777189727874762?l=fulldisclojure.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fulldisclojure.blogspot.com/feeds/8746777189727874762/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fulldisclojure.blogspot.com/2009/09/uses-for-juxt.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/8746777189727874762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6036367734290109040/posts/default/8746777189727874762'/><link rel='alternate' type='text/html' href='http://fulldisclojure.blogspot.com/2009/09/uses-for-juxt.html' title='Uses for juxt'/><author><name>Sean</name><uri>http://www.blogger.com/profile/13337863904431417843</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://3.bp.blogspot.com/_Qky4IgrZ3fg/S22nxQtq4CI/AAAAAAAAAHw/R4XDwaWXTaA/S220/Code+Picture.png'/></author><thr:total>0</thr:total></entry></feed>
