<div>2009/1/16 Peter Verswyvelen <span dir="ltr">&lt;<a href="mailto:bugfact@gmail.com">bugfact@gmail.com</a>&gt;</span></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="gmail_quote"><div class="Ih2E3d">[...]</div><div><br></div><div>After a while you decide that you need to change the Bla data type, maybe give Dog more fields, maybe completely redesign it, maybe not exposing it, but you want to keep existing code backwards compatible. With F# you can write Active Patterns for the old Dog and Cat constructors, so all existing code remains compatible. At least that is the way I understand it, but I have not actually worked yet with Active Patterns, will do so soon :)</div>
</div>
<br></blockquote></div><br><div>You get something similar with the record syntax (though, probably still not quite as powerful as the active patterns):</div><div><br></div><div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; data Blah = Dog { dogA :: Int }</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Cat { catA :: Int }</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;"><br>
</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f :: Blah -&gt; Int</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f (Dog {dogA = a}) = a</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f (Cat {catA = a}) = a</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;"><br>
</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">f (Dog { dogA = 1})</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&nbsp;&nbsp;==&gt; 1</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">f (Cat { catA = 1})</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&nbsp;&nbsp;==&gt; 1</span></div>
<div><br></div><div>If we add more fields:</div><div><br></div><div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; data Blah = Dog { dogA :: Int , dogB :: Int }</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Cat { catA :: Int , catB :: Int }</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;"><br>
</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f :: Blah -&gt; Int</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f (Dog {dogA = a}) = a</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f (Cat {catA = a}) = a</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;"><br>
</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">f (Dog {dogA = 1, dogB = 2})</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&nbsp;&nbsp;==&gt; 1</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">f (Cat {catA = 1, catB = 2})</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&nbsp;&nbsp;==&gt; 1</span></div>
<div><br></div><div>Note that the definition of &#39;f&#39; doesn&#39;t have to change. If you decide to remove that specific field, then you&#39;ll have to refactor f, but the act of adding *more* fields doesn&#39;t impact the existing definitions using record pattern matching.</div>
<div><br></div><div>The addition of record disambiguation and wildcards[1] cleans this up a bit more.</div><div><br></div><div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; {-# OPTIONS -XRecordWildCards #-}</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; data Blah = Dog { a :: Int , b :: Int , c :: Int }</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Cat { a :: Int , b :: Int }</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;"><br></span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; dog = Dog {a = 1, b = 2, c = 12}</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; cat = Cat {a = 1, b = 2}</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;"><br>
</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f :: Blah -&gt; Int</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f (Dog {..}) = a</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&gt; f (Cat {..}) = a</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;"><br></span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">f dog</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&nbsp;&nbsp;==&gt; 1</span></div>
<div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">f cat</span></div><div><span class="Apple-style-span" style="font-family: &#39;courier new&#39;, monospace;">&nbsp;&nbsp;==&gt; 1</span></div>
<div><br></div><div>So, it still might not be able to pull everything off, but it sure covers most of the bases. The cards are especially useful.</div><div><br></div><div>I &lt;3 Haskell.</div><div><br></div></div><div>/jve</div>
<div><br></div><div>[1]:&nbsp;<a href="http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html">http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html</a></div></div></div>