<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div>Further to all the playing with unamb to get some very cool behaviors, you might want to look at Olaf Chitil's paper here:</div><div><br></div><div><a href="http://www.cs.kent.ac.uk/pubs/2006/2477/index.html">http://www.cs.kent.ac.uk/pubs/2006/2477/index.html</a></div><div><br></div><div>It outlines a tool for checking if your programs are as non-strict as they can be.</div><div><br></div><div>Bob</div><br><div><div>On 21 Jan 2009, at 02:08, Conal Elliott wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite">Lovely reformulation, Ryan!<br><br>I think lub [4] is sufficient typeclass hackery for unambPatterns:<br><br>&nbsp;&nbsp; unambPatterns == lubs == foldr lub undefined<br><br>[4] <a href="http://conal.net/blog/posts/merging-partial-values">http://conal.net/blog/posts/merging-partial-values</a><br> <br>I think performance is okay now, if you have very recent versions of unamb *and* GHC head (containing some concurrency bug fixes).&nbsp; See <a href="http://haskell.org/haskellwiki/Unamb">http://haskell.org/haskellwiki/Unamb</a> .&nbsp; The GHC fix will take a while to get into common use.<br> <br>My definitions of zip via (a) 'assuming' &amp; 'unamb' and (b) parAnnihilator are badly broken.&nbsp; For one, the unamb arguments are incompatible (since i didn't check for both non-null args in the third case).&nbsp; Also, the types aren't right for parAnnihilator.<br> <br>I tried out this idea, and it seems to work out very nicely.&nbsp; See the brand-new blog post <a href="http://conal.net/blog/posts/lazier-function-definitions-by-merging-partial-values/">http://conal.net/blog/posts/lazier-function-definitions-by-merging-partial-values/</a> .&nbsp; Blog comments, please!<br> <br>&nbsp;&nbsp; - Conal<br><br><div class="gmail_quote">On Mon, Jan 19, 2009 at 3:01 PM, Ryan Ingram <span dir="ltr">&lt;<a href="mailto:ryani.spam@gmail.com">ryani.spam@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"> Actually, I see a nice pattern here for unamb + pattern matching:<br> <br> &gt; zip xs ys = foldr unamb undefined [p1 xs ys, p2 xs ys, p3 xs ys] where<br> &gt; &nbsp; &nbsp; p1 [] _ = []<br> &gt; &nbsp; &nbsp; p2 _ [] = []<br> &gt; &nbsp; &nbsp; p3 (x:xs) (y:ys) = (x,y) : zip xs ys<br> <br> Basically, split each pattern out into a separate function (which by<br> definition is _|_ if there is no match), then use unamb to combine<br> them.<br> <br> The invariant you need to maintain is that potentially overlapping<br> pattern matches (p1 and p2, here) must return the same result.<br> <br> With a little typeclass hackery you could turn this into<br> <br> &gt; zip = unambPatterns [p1,p2,p3] where {- p1, p2, p3 as above -}<br> <br> Sadly, I believe the performance of "parallel-or"-style operations is<br> pretty hideous right now. &nbsp;Conal?<br> <font color="#888888"><br> &nbsp;-- ryan<br> </font><div><div></div><div class="Wj3C7c"><br> On Mon, Jan 19, 2009 at 2:42 PM, Conal Elliott &lt;<a href="mailto:conal@conal.net">conal@conal.net</a>&gt; wrote:<br> &gt; I second Ryan's recommendation of using unamb [1,2,3] to give you unbiased<br> &gt; (symmetric) laziness.<br> &gt;<br> &gt; The zip definition could also be written as<br> &gt;<br> &gt; &nbsp; &nbsp; zip xs@(x:xs') ys@(y:ys') =<br> &gt; &nbsp; &nbsp; &nbsp; assuming (xs == []) [] `unamb`<br> &gt; &nbsp; &nbsp; &nbsp; assuming (ys == []) [] `unamb`<br> &gt; &nbsp; &nbsp; &nbsp; (x,y) : zip xs' ys'<br> &gt;<br> &gt; The 'assuming' function yields a value if a condition is true and otherwise<br> &gt; is bottom:<br> &gt;<br> &gt; &nbsp; &nbsp; assuming :: Bool -&gt; a -&gt; a<br> &gt; &nbsp; &nbsp; assuming True &nbsp;a = a<br> &gt; &nbsp; &nbsp; assuming False _ = undefined<br> &gt;<br> &gt; This zip definition is a special case of the annihilator pattern, so<br> &gt;<br> &gt; &nbsp; &nbsp; zip = parAnnihilator (\ (x:xs') (y:ys') -&gt; (x,y) : zip xs' ys') []<br> &gt;<br> &gt; where 'parAnnihilator' is defined in Data.Unamb (along with other goodies)<br> &gt; as follows:<br> &gt;<br> &gt; &nbsp; &nbsp; parAnnihilator :: Eq a =&gt; (a -&gt; a -&gt; a) -&gt; a -&gt; (a -&gt; a -&gt; a)<br> &gt; &nbsp; &nbsp; parAnnihilator op ann x y =<br> &gt; &nbsp; &nbsp; &nbsp; assuming (x == ann) ann `unamb`<br> &gt; &nbsp; &nbsp; &nbsp; assuming (y == ann) ann `unamb`<br> &gt; &nbsp; &nbsp; &nbsp; (x `op` y)<br> &gt;<br> &gt; [1] <a href="http://haskell.org/haskellwiki/Unamb" target="_blank">http://haskell.org/haskellwiki/Unamb</a><br> &gt; [2]<br> &gt; <a href="http://hackage.haskell.org/packages/archive/unamb/latest/doc/html/Data-Unamb.html" target="_blank">http://hackage.haskell.org/packages/archive/unamb/latest/doc/html/Data-Unamb.html</a><br> &gt; [3] <a href="http://conal.net/blog/tag/unamb/" target="_blank">http://conal.net/blog/tag/unamb/</a><br> &gt;<br> &gt; &nbsp; &nbsp;- conal<br> &gt;<br> &gt; On Mon, Jan 19, 2009 at 12:27 PM, Ryan Ingram &lt;<a href="mailto:ryani.spam@gmail.com">ryani.spam@gmail.com</a>&gt; wrote:<br> &gt;&gt;<br> &gt;&gt; On Mon, Jan 19, 2009 at 9:10 AM, ChrisK &lt;<a href="mailto:haskell@list.mightyreason.com">haskell@list.mightyreason.com</a>&gt;<br> &gt;&gt; wrote:<br> &gt;&gt; &gt; Consider that the order of pattern matching can matter as well, the<br> &gt;&gt; &gt; simplest<br> &gt;&gt; &gt; common case being zip:<br> &gt;&gt; &gt;<br> &gt;&gt; &gt; zip xs [] = []<br> &gt;&gt; &gt; zip [] ys = []<br> &gt;&gt; &gt; zip (x:xs) (y:ys) = (x,y) : zip xs ys<br> &gt;&gt;<br> &gt;&gt; If you are obsessive about least-strictness and performance isn't a<br> &gt;&gt; giant concern, this seems like a perfect use for Conal's unamb[1]<br> &gt;&gt; operator.<br> &gt;&gt;<br> &gt;&gt; zipR xs [] = []<br> &gt;&gt; zipR [] ys = []<br> &gt;&gt; zipR (x:xs) (y:ys) = (x,y) : zip xs ys<br> &gt;&gt;<br> &gt;&gt; zipL [] ys = []<br> &gt;&gt; zipL xs [] = []<br> &gt;&gt; zipL (x:xs) (y:ys) = (x,y) : zip xs ys<br> &gt;&gt;<br> &gt;&gt; zip xs ys = unamb (zipL xs ys) (zipR xs ys)<br> &gt;&gt;<br> &gt;&gt; This runs both zipL and zipR in parallel until one of them gives a<br> &gt;&gt; result; if neither of them is _|_ they are guaranteed to be identical,<br> &gt;&gt; so we can "unambiguously choose" whichever one gives a result first.<br> &gt;&gt;<br> &gt;&gt; &nbsp;-- ryan<br> &gt;&gt;<br> &gt;&gt; [1]<br> &gt;&gt; <a href="http://conal.net/blog/posts/functional-concurrency-with-unambiguous-choice/" target="_blank">http://conal.net/blog/posts/functional-concurrency-with-unambiguous-choice/</a><br> &gt;&gt; _______________________________________________</div></div></blockquote></div><br> _______________________________________________<br>Haskell-Cafe mailing list<br><a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>http://www.haskell.org/mailman/listinfo/haskell-cafe<br></blockquote></div><br></body></html>