There is unsurprisingly a run time exception thrown by the following code :
data Necklace = InvalidNecklace |
Necklace { necklace_id :: Int, meow :: Int, ... }
necklace_id InvalidNecklace
Is there some natural way to define a value for necklace_id when applied to InvalidNecklace to take a value rather than throwing an exception?
GHC fails with a multiple declarations error for `necklace_id' if I try the obvious thing :
necklace_id InvalidNecklace = -1
Is there perhaps some pragma that'll tell GHC to replace it's inferred declaration by this declaration?
I could declare InvalidNecklace to be a record by adding { necklace_id :: Int }, but afaik I cannot guarantee it always returns -1, and generally makes a horrible mess. I could simply define :
get_necklace_id InvalidNecklace = -1
get_necklace_id x = necklace_id x
but this partially defeats the purpose of records.
I suppose one could create a special invalidNecklace value by writing :
invalidNecklace = Necklace { necklace_id = -1,
meow = error "meow invalidNecklace accessed", ... }
Are there any disadvantages to this second approach? I certainly lose the ability to make meow strict or unpacked, but perhaps separate debugging and optimized versions could be maintained. Is there a pragma to locally disable warnings for partially initialized records?
(UPDATED BELOW)
As you discovered, the getter defined by the
Necklacedeclaration cannot be further defined. There is no pragma to change this.The common practice in Haskell would be to use this style:
Using a magic return value of "-1" is common style in C-type languages with simpler type systems. But note that
Maybe Intis isomorphic toNecklace, so it adds little in the simplest case (except access to the large number of common functions for handlingMaybethat may not exist forNecklace). If you makeNecklacemore complicated thenget_necklace_idmakes sense.For larger projects it is possible to have template Haskell or an extra tool automatically create the
get_necklace_idabove.UPDATE: Using
fromJustis not a particularly good idea. To get "reasonable defaults" and "no failure modes" you may compose theget_necklace_id :: Necklace -> Maybe IntwithData.Maybe.fromMaybe :: a -> Maybe a -> a(one of the common Maybe handling functions) like this:The
a_necklace_idis identical to your function that replaces InvalidNecklace with (-1). Code that needs a different default can usefrom_necklace_id.