[Haskell-cafe] Re: Adding a field to a data record

Malcolm Wallace Malcolm.Wallace at cs.york.ac.uk
Tue Jul 28 11:07:58 EDT 2009


> the part I would really like to avoid is writing the
> New.Foo { a=a, b=b, ... z=1 } part, where the field
> names are many, long, and varied.

OK, here is another hack-ish trick, since I notice your data is stored  
on disk as text, using "show".  I assume you are using something like  
Read to retrieve it.  Well, how about using a real parser instead?   
The parser during conversion can be slightly more lax, automatically  
adding in the extra field.

For instance, using polyparse's Text.Parse, and DrIFT to derive the  
appropriate Parse instance for your datatype:

     module Foo where
     data Foo = Foo { a :: Int
                    , b :: Bool
                    , c :: Maybe Foo }
       {-! derive : Parse !-}

DrIFT gives you this instance:

     {-* Generated by DrIFT : Look, but Don't Touch. *-}
     instance Parse Foo where
         parse = constructors
	    [ ( "Foo"
	      , return Foo `discard` isWord "{" `apply` field "a"
		       `discard` isWord "," `apply` field "b"
		       `discard` isWord "," `apply` field "c"
		       `discard` isWord "}"
	      )
	    ]

Let's say the field 'b' is new, and your existing data does not have  
it.  So just take the parser generated by DrIFT and make a small  
modification:

     {-* Generated by DrIFT but modified by hand for conversion  
purposes *-}
     instance Parse Foo where
         parse = constructors
	    [ ( "Foo"
	      , return Foo `discard` isWord "{" `apply` field "a"
		       `apply` return True -- this field does not yet exist in data
		       `discard` isWord "," `apply` field "c"
		       `discard` isWord "}"
	      )
	    ]

Then do the obvious thing: parse the old data, immediately write it  
out again, and then throw away the modified parser in favour of the  
pure generated one.

Regards,
     Malcolm


More information about the Haskell-Cafe mailing list