Question

We can't do read someValue :: someDataType or show someValue for every type because deriving (Show, Read) has to be written in the data declarations. Is there a case, other than mistake, where we don't want our type to be serializable? Why is Show separated from Read? Is there a case, other than mistake, we only want to show some data and not read it? If not, why not have a single data type Serializable?

Just now, I'm using the Key datatype of the Gloss library which derives Show and not Read, which I don't understand. It's a shame because I wanted to put the configuration of the controls in a file and then read it, so the player can change the controls and have his own configuration. I had to do wrappers for Key, SpecialKey and MouseButton, which is not a big deal but is useless.

data Key' = Char' Char | SpecialKey' SpecialKey | MouseButton' MouseButton
    deriving (Eq, Ord, Show, Read)
convertKey x = case x of
    Char' c -> Char c
    SpecialKey' sk -> SpecialKey sk
    MouseButton' mb -> MouseButton mb
Was it helpful?

Solution

Why is Show separate from Read

I don't know why this was originally, but feel it should persist because some (very few) types can be shown, or have a placeholder string shown, but not read back in. Functions are the typical example.

Another way to think about it: It's very easy to place things in separate classes but very hard to deal with too many functions in one class that doesn't always make sense in the same contexts. Many people feel the Num class is a prime example of this issue.

How Can I read Key and other types not in Read

Step one: send in a patch adding Read to the set of derived instances. Step two: make a work around by using standalone deriving:

{-# LANGUAGE StandaloneDeriving #-}
deriving instance Show Key

Step three: Use CPP to make your code work with either version of the codebase, be it the Gloss library with a Read instances that Ben will someday release or the version without.

Why isn't there a Serializable class?

For starters, there is a Serialize class. Also, text is a horrible way to serialize things. Perhaps you'd want a lazier serialize class in which case you should see the Binary class. If you're concerned about performance then you might like blaze-builder, though I've honestly never used it.

OTHER TIPS

First, not all data types can be shown, for instance functions cannot be shown, so not all data types can be shown (nor read). The original Haskell definition specified that if no deriving clause was given then as many derived classes as is possible would be derived. This made it difficult to know what classes were actually derived, so the Haskell definition was changed to force explicit deriving clauses.

Second, in the original Haskell definition the show and read functions where bundled together in the Text class. This isn't much of a problem when you derive Show and Read, but it is a pain when you write them by hand. You often want to define a special show function, but now you are forced to write a read function as well, so it's better to keep them separate. Personally I almost always derive Show, but almost never Read.

The Show and Read classes are not really meant to be used for serialization, but rather for simple input and output.

Not every type is serializable. How can you establish an isomorphism between String -> String and String? If you give me Read and Show instances for String -> String, I can find a function which isn't serialisable like this:

evil :: String -> String
evil s = map succ (read s s ++ " evil")

Suppose

read (show evil) = evil

We get

evil (show evil)
  = map succ (read (show evil) (show evil) ++ " evil")
  = map succ (evil (show evil) ++ " evil")
  = map succ (evil (show evil)) ++ "!fwjm"

so if evil (show evil) is defined, then it has a first character c satisfying c = succ c, which is impossible.

In general, functions can't be serialized. Sometimes, we write datatypes which pack up functions, so not every datatype is serializable either. E.g.,

data Psychiatrist
  = Listen (String -> Psychiatrist)
  | Charge Int

Sometimes, even for these types, you might choose to provide partial implementations of Read (with some cases missing) and Show (e.g., with placeholders for or tabulations of functions), but there is no canonical way to choose them or reason why you would expect both.

As others have mentioned, serious serialization is the preserve of Serialize. I tend to use Show and Read for diagnostic purposes, especially trying things out in ghci. For that purpose, Show is by far more useful, because ghci has a Haskell parser to do the reading.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top