Pattern matching 'undefined'

Derek Elkins ddarius@hotpop.com
Tue, 27 May 2003 07:54:20 -0400


On Mon, 26 May 2003 23:50:27 +0200
Alain Cremieux <alcremi@pobox.com> wrote:

> Derek Elkins wrote:
> 
> >On Sun, 25 May 2003 23:28:02 +0200
> >Alain Cremieux <alcremi@pobox.com> wrote:
> 
> >  
> 
> >>data UR = MkUR {
> >>                 fieldA :: Int,
> >>                 fieldB :: Int,
> >>                 fieldC :: String
> >>                 }
> >>           deriving (Show)
> >>
> >>and, for example, we have
> >>
> >>testUR  = MkUR {fieldA = 1}
> >>testUR' = MkUR {fieldA = 2, fieldB = 3, fieldC = "C"}
> >>
> >>Now I want to write a function which transforms my datatype in
> >>[(String, String)] where a (key, value) element exists if the field
> >is>present, and none if the field does not exist.
> >>
> >>attrList :: UR -> [(String, String)]
> >>attrList u =  al "fieldA" (fieldA u)
> >>           ++ al "fieldB" (fieldB u)
> >>           ++ al "fieldC" (fieldC u)
> >>          
> >>al :: (Show a) => String -> a -> [(String, String)]
> >>al fn fv = [(fn, show fv)]
> >>    
> >>
> 
> >(Wouldn't it make more sense to do attrList u = [al "fieldA" (fieldA
> >u), al ...] with al :: ... -> (String,String)?)
> >  
> 
> 
> The idea is that the list may be empty, thus the choice of a list of 
> pairs instead of a simple pair

But al (obviously) will never make an empty list.  Also below Maybe
(String,String) serves the same purpose.  You use Maybe when you want to
return 0 or 1 thing, and lists when you want to return 0 or many.

> >>Of course, as written, "attrList testUR'" succeeds and "attrList
> >>testUR" fails (Missing field in record construction Main.fieldB)
> >>I need to match against undefined, which is impossible.
> >>    
> >>
> >So reify undefined.
> >  
> 
> How can I do that ? Can you give me an example ?

That's what the Nothing constructor does.

> >>Is there a solution (probably involving irrefutable patterns, ~) ? 
> >>    
> >>
> 
> >You want values that may or may not be there.  The standard solution
> >is the Maybe type.  Assuming you don't want to print out, "Just
> >\"C\"", you can either make your own type with your own instance of
> >show, or use a showValue function in al.  The latter is likely
> >preferable as there are quite a few utility functions for the Maybe
> >type already and it's more familiar.  You can define al with type ...
> >-> Maybe (String,String) and attrList would just be catMaybes over a
> >list of them, assuming you want attrList(MkUR (Just 5) Nothing (Just
> >"Hello")) to give you[("fieldA","5"),("fieldC","\"Hello\"")]
> >otherwise al can be ... ->(String, Maybe String) and you'd change
> >show fv to fmap show fv, or just... -> (String,String) with
> >("fieldB","undefined"/"Nothing"/""/whatever)
> >  
> 
> The problem is that there may be 50 fields (my example was too simple,
> sorry). So I want precisely to avoid 'Just' and 'Nothing', because I 
> want to be able to say :
> graph = AttrGraphDot {color = Blue}
> without having to name the 49 other fields.
> Field labels seem really adequate to do this, and by having defined
> the type Color with Red | Blue | ... there will be a compile-time
> check on the correctness of the value. This would be impossible with
> an ordinary implementation : [(String, String)]  which will be
> verified only at run-time.
> But then I must be able to convert the field-labelled datatype to a
> list [(String, String)], depending on which labels have been provided.
> This is not so easy, especially since it is not possible to 
> pattern-match against field labels, which are functions.

John Meacham gave you a good answer for the first part.  And you
certainly CAN pattern-match against field labels, e.g.
foo ({ fieldA = Just 5, fieldB = Just x, fieldC = Nothing }) = x
foo ({ fieldA = Just x }) = 0