Are there any default values ​​for entries in Haskell?

Not surprisingly, a runtime exception is thrown by the following code:

data Necklace = InvalidNecklace | Necklace { necklace_id :: Int, meow :: Int, ... } necklace_id InvalidNecklace 

Is there any natural way to define a value for necklace_id when applied to InvalidNecklace to accept a value rather than throw an exception?

The GHC fails with a multiple declaration error for `necklace_id 'if I try to do the obvious thing:

 necklace_id InvalidNecklace = -1 

Is there some kind of pragma that will tell the GHC to replace its proposed announcement with this announcement?

I could declare InvalidNecklace record by adding { necklace_id :: Int } , but afaik I can’t guarantee that it always returns -1, and usually makes a terrible mess. I could just determine:

 get_necklace_id InvalidNecklace = -1 get_necklace_id x = necklace_id x 

but this partially violates the purpose of the records.

I believe that you can create a special InvalidNecklace value by writing:

 invalidNecklace = Necklace { necklace_id = -1, meow = error "meow invalidNecklace accessed", ... } 

Are there any flaws in this second approach? Of course, I lose the ability to make meow strict or unpacked, but perhaps you can save separate debugging and optimized versions. Is there a pragma for locally disabling alerts for partially initialized entries?

+4
source share
2 answers

(UPDATED BELOW)

As you have discovered, a getter defined by a Necklace declaration cannot be further defined. There is no pragma to change this.

A common practice in Haskell will be to use this style:

 get_necklace_id :: Necklace -> Maybe Int get_necklace_id InvalidNecklace = Nothing get_necklace_id (Necklace x) = Just x 

Using the magic return value of -1 is a common style in C-type languages ​​with simpler type systems. But keep in mind that Maybe Int is isomorphic to Necklace , so it adds little in the simplest case (except for access to a large number of general functions for Maybe processing, which may not exist for Necklace ). If you make Necklace more complicated then get_necklace_id makes sense.

For large projects, you can create a Haskell template or an additional tool that automatically creates the get_necklace_id above.

UPDATE: Using fromJust not a particularly good idea. To get “reasonable defaults” and “no failure modes”, you can compose get_necklace_id :: Necklace -> Maybe Int with Data.Maybe.fromMaybe :: a -> Maybe a -> a (one of the usual Maybe processing functions ) in the following way:

 from_necklace_id :: Int -> Necklace -> Int from_necklace_id default = fromMaybe default . get_necklace_id a_necklace_id :: Necklace -> Int a_necklace_id = from_necklace_id (-1) 

a_necklace_id is identical to your function, which replaces InvalidNecklace with (-1). Code that requires a different default value may use from_necklace_id .

+8
source

Why don't you have a Necklace type representing only valid necklaces, and perhaps a necklace for cases where the necklace may be invalid? Or, avoiding the use of Maybe, something like this (note that I'm still not sure what a good naming convention is here):

 data Necklace = InvalidNecklace | NecklaceData NecklaceData data NecklaceData = NecklaceDataRec { necklace_id :: Int, meow :: Int, ... } 
+4
source

Source: https://habr.com/ru/post/1392943/


All Articles