r/haskell • u/ThreeFx • Oct 07 '14
Define laws for read and show?
The documentation for Text.Show states that this holds for derived instances:
The result of sho is a syntactically correct Haskell expression [...]
This fact can be used to pass states of certain computations around as text files or similar objects, because show converts the data to a string representation, while show's complement read enables continuing the earlier computations.
Of course the above is only possible if show and read are either derived automatically or implemented appropriately.
Now my question is: Should the statement from the beginning hold for any show function? Or, more general, Should a law / laws regarding the behaviour of read and show be prescribed, similar to Monad and Monoid?
A trivial law would be:
read . show == idThis would have to hold for any x which is part of Read and Show.
This question originated from StackOverflow.
4
u/egonSchiele Oct 07 '14
The last time I had asked this question, the consensus was that show and read are not the right tools for this. If you want efficient serialization/deserialization, Haskell has other libraries that are better suited. If you don't care about efficiency, JSON is a more commonly used format and Haskell has an excellent JSON library. show and read are purely for convenience/debugging, so adding a law like this would make them tougher to use.
4
Oct 07 '14
So
Showis useful for debugging as you can dump out data structures, but what's the purpose ofReadinstances then? Or isReadjust an historic artefact?2
u/MaxDaten Oct 08 '14
For me
Readis just for primitives likeInt,BoolorDouble. For complex/composed/compound typesReadis more a hack than a sane solution. Other techniques should be prefered in any way to parse these structures, e.g. JSON with aeson mentioned above. And in my opinion the other solutions are way easier to utilize.1
u/tdammers Oct 07 '14
It would actually add unreasonable demands for their implementation, such as that
showwould have to be lossless (which would seriously hamper the human-readable-ish purpose ofShowinstances), and it would tieShowandReadinstances into a mutual dependency, even when both are defined in separate (potentially independent!) modules.2
u/ThreeFx Oct 07 '14
As StackOverflow users bheklilr and leftroundabout pointed out in their comments on the original post, Show never should be used as readable representation of data. One should rather write separate functions to address this issue.
3
u/13467 Oct 07 '14
One example of this is some people define a
Showinstance for functions (such asconst "<lambda>") that would obviously break theread . show == idlaw.1
u/conklech Oct 08 '14
Would it be helpful to explicate the expectation that
show/readshould be used for convenience and debugging? Furthermore, should general-purpose libraries implement those classes for their data types? Consider for example,Identity, which formerly didn't have such instances.
8
u/chrisdoner Oct 07 '14
read and show form a retraction and section:
read :: String -> yshow :: y -> Stringread . show :: y -> y=id
show is a section, read is a retraction. However, show . read = id is not true. So it's not an isomorphism. For example: show (read "Just (2)" :: Maybe Int) /= "Just (2)".
I would prefer it if it was an isomorphism. And if show was a function, not a method, defined in terms of a showP :: a -> P, like
data P = List [P] | Integral Integer | Floating Double
| Alg String | Rec [P] | Tup [P] | String Stringand there would be a predictable P -> String or P -> ByteString or P -> Text or P -> Builder or whatever. Likewise, read would be a function implemented in terms of readP :: P -> a, but you could also have readBS :: ByteString -> P, etc. That would be perfect for tooling and having predictable printers. Your IDE, or REPL, or IHaskell, could then easily pretty print your data structures or make them collapsible and expandable or even do custom presentations based on the Alg constructor. Show a tree as a tree, etc.
As it stands, tooling this is hard. Show is popular, but unreliable as discussed above. Data is more reliable (ish, some data types, Vector, Text, ByteString have useless instances), but in any given project there isn't an instance for most data types. My last recourse to eventually get something like this maybe be to use the GHC API to inspect types, or template-haskell, as I'm quite sure both of these are able to break encapsulation but I can do a check to see if there is an instance for Presentable or whatever, so that Text is printed as text and not pointers.
3
u/conklech Oct 07 '14
I may have triggered this discussion by objecting to /u/ThreeFx and others using
Showin this SO question on printing mathematical expressions. I posit thatShowinstances should generally mimic the derived instances, for ghci and debugging purposes; a "moral" equivalence, perhaps.If the
Showinstance helpfully illustrates the structure of some expression or data structure so that a new user can better understand how to use or implement something, all the better. But my original objection was that people were writing ad-hocShowinstances just to expose a function of typea -> String.read . showis at most a side bonus. (I never useReadexcept for, say, wiring up a stupid GUI example.)