<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Random Hacks: McCarthy's Ambiguous Operator</title>
    <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Technology and Other Fun Stuff</description>
    <item>
      <title>"McCarthy's Ambiguous Operator" by person-b</title>
      <description>&lt;p&gt;This reminds me of Damian Conway&amp;#8217;s Positronic::Variables &lt;span class="caps"&gt;CPAN &lt;/span&gt;Perl module. He wrote it for his (hilarious &amp;#8211; highly recommended) talk on &amp;#8220;Temporally Quaquaversal Virtual Nanomachine Programming In Multiple Topologically Connected Quantum-Relativistic Parallel Timespaces&amp;#8230;Made Easy!&amp;#8221; (http://blip.tv/file/1145545/). It actually did look into the future.&lt;/p&gt;</description>
      <pubDate>Fri, 03 Jul 2009 18:32:36 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:2fcd585c-1651-48c3-8008-8244296c24fd</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-645</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by backtrack</title>
      <description>&lt;p&gt;There&amp;#8217;s also goal directed computation as implemented in the Icon language, though you probably know about it.&lt;/p&gt;</description>
      <pubDate>Tue, 09 Sep 2008 12:40:37 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:365e170d-4cf4-4f79-b509-2a6c77d740df</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-583</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Doug Auclair</title>
      <description>&lt;p&gt;The Haskell version of &lt;span class="caps"&gt;SEND&lt;/span&gt;+MORE=MONEY in the amb-style:&lt;/p&gt;


&lt;pre&gt;
&amp;gt; sendmory = [(s,e,n,d,m,o,r,y) | s &amp;lt;- pos, e &amp;lt;- all, n &amp;lt;- all, d &amp;lt;- all,
&amp;gt;                                 m &amp;lt;- [1], o &amp;lt;- all, r &amp;lt;- all, y &amp;lt;- all,
&amp;gt;                                 y  d + e || y  d + e &amp;#8211; 10,
&gt;                                 s &lt;ins&gt; m &lt;/ins&gt; 1 &gt;= 10, 
&gt;                                 num [s,e,n,d] + num [m,o,r,e]
&gt;                                       == num [m,o,n,e,y],
&gt;                                 allDiff [s,e,n,d,m,o,r,y]]
&gt;   where
&gt;     pos = [2..9]
&gt;     all = 0:pos

&lt;blockquote&gt;
	&lt;p&gt;num :: [Int] &amp;rarr; Int
	num = foldl ((+).(*10)) 0&lt;/p&gt;

&lt;/blockquote&gt;




&gt; allDiff :: [Int] &amp;rarr; Bool
&gt; allDiff [] = True
&gt; allDiff (x:xs) = notElem x xs &amp;#38;&amp;#38; allDiff xs
&lt;/pre&gt;

	&lt;p&gt;... note that a definition for amb is unnecessary, as list compression (as a MonadPlus) already makes choice.&lt;/p&gt;


	&lt;p&gt;The above, as already pointed out, is not very efficient, so using a state monad to narrow the selection in-place:&lt;/p&gt;


&lt;pre&gt;
&amp;gt; sendmory' :: StateT [Int] [] [Int]
&amp;gt; sendmory' = -- do [m] &amp;lt;- item
&amp;gt;             --    verify (m == 1)
&amp;gt;             -- the first two lines can be written 'do let m = 1'
&amp;gt;             -- iff the passed in list does not contain the number 1
&amp;gt;             do let m = 1
&amp;gt;                [s] &amp;lt;- item
&amp;gt;                verify (s + m + 1 &amp;gt;= 10)
&amp;gt;                [e] &amp;lt;- item
&amp;gt;                [d] &amp;lt;- item
&amp;gt;                [y] &amp;lt;- item
&amp;gt;                verify (y  d + e || y  d + e &amp;#8211; 10)
&gt;                [n] &lt;- item
&gt;                [o] &lt;- item
&gt;                [r] &lt;- item
&gt;                verify (num [s,e,n,d] + num [m,o,r,e]
&gt;                                    == num [m,o,n,e,y])
&gt;               &amp;#8212;item obviates allDiff
&gt;                return [s,e,n,d,m,o,r,y]
&gt;

&lt;blockquote&gt;
	&lt;p&gt;&amp;#8212;split list into all combinations of one element and rest
	splits :: [a] &amp;rarr; [([a],[a])]
	splits l = splitAccum [] l where
  splitAccum ys []     = []
  splitAccum ys (x:xs) = ([x],xs++ys) : splitAccum (x:ys) xs&lt;/p&gt;

&lt;/blockquote&gt;




&lt;blockquote&gt;
	&lt;p&gt;choose :: StateT &lt;a href="a"&gt;a&lt;/a&gt; [a]
	choose = StateT $ \s &amp;rarr; splits s&lt;/p&gt;

&lt;/blockquote&gt;




&lt;blockquote&gt;
	&lt;p&gt;item :: StateT &lt;a href="Int"&gt;Int&lt;/a&gt; [Int]
	item = choose&lt;/p&gt;

&lt;/blockquote&gt;




&gt; verify :: Bool &amp;rarr; StateT &lt;a href="Int"&gt;Int&lt;/a&gt; ()
&gt; verify p = StateT $ \s &amp;rarr; if p then [((), s)] else []
&lt;/pre&gt;

	&lt;p&gt;splits, choose, and verify are thanks to Dirk Thierbach on comp.lang.haskell.  This version is 200x faster than the amb-style one&amp;#8212;10x speed up for redundant digit elimination and on top of that a 20x speed up from placing the guards as far up in the computation as possible.  Although it requires some helper functions to implement nondeterminism with elimination, sendmory&amp;#8217; retains the declarative feel of it&amp;#8217;s amb-styled counterpart.&lt;/p&gt;</description>
      <pubDate>Thu, 29 Nov 2007 18:49:38 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:52018815-1dfb-47c8-a358-175fcca0bc43</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-541</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Doug Auclair</title>
      <description>&lt;p&gt;@Christian, you are quite right!  For this particular problem (SEND+MORE=MONEY), eliminated selected digits narrows the search-space considerably, speeding up the calculation by a factor of ~50:&lt;/p&gt;


	&lt;p&gt;http://www.cotilliongroup.com/arts/DCG.html&lt;/p&gt;


	&lt;p&gt;(done with Prolog&amp;#8217;s definite clause grammars, which have a similar feel to Haskell&amp;#8217;s monads)&lt;/p&gt;


	&lt;p&gt;And, I suppose, one can use, e.g., Gwydion Dylan&amp;#8217;s matrix library (http://www.opendylan.org/gdref/gdlibs/libs-matrix-operations.html), along the lines of a gausse-jordan elimination, to solve the system of equations linearly? Perhaps not apropos to this problem, but handles several kinds of constraint problems.&lt;/p&gt;</description>
      <pubDate>Wed, 28 Nov 2007 15:54:11 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:a4d92ae3-9bd1-4330-a605-a24f08d1fb84</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-537</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Christian Theil Have</title>
      <description>&lt;p&gt;&amp;#8220;Since a backtracking search takes O(2^N) time (yikes!), it’s worth doing a lot of work before actually branching.&amp;#8221;&lt;/p&gt;


	&lt;p&gt;This really depends on the nature of the problem. If you are only going to backtrack a little, it might not be worth spend cycles on forward-checking or ensuring arc consistency. Propagation can also be quite costly.&lt;/p&gt;


	&lt;p&gt;But sure, in most cases, amb is not a very efficient way solving constraint problems..&lt;/p&gt;</description>
      <pubDate>Fri, 08 Jun 2007 08:17:17 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:77886418-508f-4b7f-aba2-9cfcdc439d53</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-465</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Eric Kidd</title>
      <description>&lt;p&gt;Wow! That&amp;#8217;s very cool.&lt;/p&gt;


	&lt;p&gt;If you&amp;#8217;re into constraint languages, you might also enjoy &lt;a href="http://www.mozart-oz.org/"&gt;Oz&lt;/a&gt;, which can do heavily-optimized searches of constraint problems.&lt;/p&gt;


	&lt;p&gt;The big advantage of Oz: Before choosing which path to investigate, it tries to infer as much information as possible (aka &amp;#8220;propagation&amp;#8221;). And then it makes very intelligent guesses about exactly which &amp;#8220;guess&amp;#8221; to make next (aka &amp;#8220;distribution&amp;#8221;).&lt;/p&gt;


	&lt;p&gt;Since a backtracking search takes O(2^N) time (yikes!), it&amp;#8217;s worth doing a &lt;em&gt;lot&lt;/em&gt; of work before actually branching.&lt;/p&gt;


	&lt;p&gt;And the most popular implementation of Oz can actually spread the search over an entire cluster of computers!&lt;/p&gt;</description>
      <pubDate>Sun, 21 Jan 2007 11:51:06 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:3398b76a-e2cf-462c-84e5-3a98d3ed5cba</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-235</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Ben</title>
      <description>&lt;p&gt;Wow, I just implemented the send+more=money solver with amb:&lt;/p&gt;


&lt;pre&gt;

# define variables
m = 1
n = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
o = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
r = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
s = amb(2, 3, 4, 5, 6, 7, 8, 9)
y = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
e = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
d = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)

# reduce the problem space
amb unless(d+e  y || d+e  y+10)
amb unless(s+m+1 &gt;= 10)

	&lt;ol&gt;
	&lt;li&gt;The actual problem
send = s&lt;strong&gt;1000 &lt;ins&gt; e&lt;/strong&gt;100 &lt;/ins&gt; n&lt;strong&gt;10 + d
more = m&lt;/strong&gt;1000 &lt;ins&gt; o&lt;strong&gt;100 &lt;/ins&gt; n&lt;/strong&gt;10 + e
money = m&lt;strong&gt;10000 &lt;ins&gt; o&lt;/strong&gt;1000 &lt;/ins&gt; n&lt;strong&gt;100 &lt;ins&gt; e&lt;/strong&gt;10 &lt;/ins&gt; y
amb unless(send+more == money)&lt;/li&gt;
	&lt;/ol&gt;


	&lt;ol&gt;
	&lt;li&gt;p &amp;#8220;m=#{m}, n=#{n},  o=#{o}, r=#{r}, s=#{s}, y=#{y}, e=#{e}, d=#{d},&amp;#8221;&lt;/li&gt;
	&lt;/ol&gt;


	&lt;ol&gt;
	&lt;li&gt;Make sure all variables are different
a = [m, n, o, r, s, y, e, d]
t = Array.new(10, 0)
a.each { |v| amb unless (t[v]+=1)&lt;2 }&lt;/li&gt;
	&lt;/ol&gt;


	&lt;ol&gt;
	&lt;li&gt;stop
cut&lt;/li&gt;
	&lt;/ol&gt;


p &amp;#8220;Final solution: m=#{m}, n=#{n},  o=#{o}, r=#{r}, s=#{s}, y=#{y}, e=#{e}, d=#{d},&amp;#8221; 
&lt;/pre&gt;

	&lt;p&gt;Amb is pretty cool!
Ben&lt;/p&gt;</description>
      <pubDate>Wed, 17 Jan 2007 12:05:24 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:4150c877-da90-49a5-a235-031034a4c7d9</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-231</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Ben</title>
      <description>&lt;p&gt;Thats really interesting.
It means that you could write a constraint &lt;span class="caps"&gt;DSL&lt;/span&gt; in Ruby or any other language which implements continuations. I thought constraint engines were hard&amp;#8230;&lt;/p&gt;


	&lt;p&gt;Cheers
Ben&lt;/p&gt;</description>
      <pubDate>Wed, 17 Jan 2007 06:58:29 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:1d2c6985-5144-43e7-9d14-2c01dac14d3c</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-230</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Dan Piponi</title>
      <description>&lt;p&gt;I have an implementation of &amp;#8220;amb&amp;#8221; that can be used in C &lt;a href="http://homepage.mac.com/sigfpe/Computing/continuations.html"&gt;here&lt;/a&gt;. Thanks for giving a name to this operator for me &amp;#8211; I never knew what to call it.&lt;/p&gt;</description>
      <pubDate>Wed, 22 Feb 2006 19:32:06 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:52440908-5880-4154-aed6-2629d690ebcb</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-174</link>
    </item>
    <item>
      <title>McCarthy's Ambiguous Operator</title>
      <description>    &lt;p&gt;Back in 1961, John McCarthy (the inventor of LISP) &lt;a href='http://citeseer.ist.psu.edu/mccarthy63basis.html'&gt;described&lt;/a&gt;
    an interesting mathematical operator called &lt;code&gt;amb&lt;/code&gt;.  Essentially,
    &lt;code&gt;amb&lt;/code&gt; &lt;i&gt;hates&lt;/i&gt; to be called with no arguments, and can look
    into the future to keep that from happening.  Here's how it might look
    in Ruby.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2005/10/11/amb-operator"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Tue, 11 Oct 2005 00:00:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:8d29ae6d-81d0-4f48-a6cb-80187e1821a7</guid>
      <author>Eric</author>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator</link>
      <category>Ruby</category>
      <category>Continuations</category>
      <category>Hacks</category>
      <category>Recommended</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/70</trackback:ping>
    </item>
  </channel>
</rss>
