
2009/1/16 Peter Verswyvelen
[...]
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 :)
You get something similar with the record syntax (though, probably still not quite as powerful as the active patterns):
data Blah = Dog { dogA :: Int } | Cat { catA :: Int }
f :: Blah -> Int f (Dog {dogA = a}) = a f (Cat {catA = a}) = a
f (Dog { dogA = 1}) ==> 1 f (Cat { catA = 1}) ==> 1 If we add more fields:
data Blah = Dog { dogA :: Int , dogB :: Int } | Cat { catA :: Int , catB :: Int }
f :: Blah -> Int f (Dog {dogA = a}) = a f (Cat {catA = a}) = a
f (Dog {dogA = 1, dogB = 2}) ==> 1 f (Cat {catA = 1, catB = 2}) ==> 1 Note that the definition of 'f' doesn't have to change. If you decide to remove that specific field, then you'll have to refactor f, but the act of adding *more* fields doesn't impact the existing definitions using record pattern matching. The addition of record disambiguation and wildcards[1] cleans this up a bit more.
{-# OPTIONS -XRecordWildCards #-} data Blah = Dog { a :: Int , b :: Int , c :: Int } | Cat { a :: Int , b :: Int }
dog = Dog {a = 1, b = 2, c = 12} cat = Cat {a = 1, b = 2}
f :: Blah -> Int f (Dog {..}) = a f (Cat {..}) = a
f dog ==> 1 f cat ==> 1 So, it still might not be able to pull everything off, but it sure covers most of the bases. The cards are especially useful. I <3 Haskell. /jve [1]: http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html