Discussion: adding displayException to Exception class

I don't want to make a format proposal yet, just open up discussion on an issue, and see how others feel about it. As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read). However, there's at least one use case in base which explicitly uses Show for non-serialization purposes: the Exception class. All instances of Exception are required to have an instance of Show, but there's no way to actually serialize exceptions generally[2]. So by construction and by practice, the Show instance for Exception is used exclusively for the latter two categories I mentioned (debug info and user-friendly data display). As a result of that, it's quite common[3] to define a Show instance for exception types that is *not* serializable, but rather user friendly. This however seems to contradict what is accepted as good practice in general. I have a possible solution that I'd like to propose as a strawman: add a new method to the Exception typeclass: displayException :: e -> String displayException = show The name is up for debate, but I chose `display` since it seems to already be used elsewhere for user-friendly output. Other possible choices are showException or prettyException. The default implementation will reuse the Show instance, so no user code will be broken by this[4]. In the short term, the only other change I'd recommend is that the default exception handler use `displayException` instead of `show` for printing uncaught exceptions. Longer term, after deprecation cycles, we could consider removing the Show superclass from Exception. Again, this isn't a real proposal (yet), I'm more interested now in what people think about such a change. Michael [1] http://www.haskell.org/pipermail/libraries/2014-October/023957.html [2] Both due to how extensible exceptions work, and due to the lack of a Read superclass. [3] This discussion started when Chris Done and I were working with the tar package, which defines custom renderings for FormatError. I've implemented this same technique in some of my libraries, and I'm sure there are many other examples on Hackage. [4] Barring the standard issue of new identifiers clashing with identifiers defined locally.

I like the proposal. I think, though, that it needs more motivation: "is it just to be consistent with most other Show instances?" Personally, I think it will be nice to be able to quickly identify the constructor of the exception. Currently one has Google for the error message and hope for the best. Cheers, -- Felipe.

Thank you for pointing that out. As it happens, that's the exact
conversation Chris and I had which led to this email ;).
On Wed, Oct 29, 2014 at 2:09 AM, Felipe Lessa
I like the proposal. I think, though, that it needs more motivation: "is it just to be consistent with most other Show instances?"
Personally, I think it will be nice to be able to quickly identify the constructor of the exception. Currently one has Google for the error message and hope for the best.
Cheers,
-- Felipe.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Hi Michael,
Personally, I think it will be nice to be able to quickly identify the constructor of the exception. Currently one has Google for the error message and hope for the best.
Thank you for pointing that out. As it happens, that's the exact conversation Chris and I had which led to this email ;).
Same thought here, one of my main complaints about the current state of exceptions is that the default exception handler gives you no hint about the type of uncaught exceptions. For me uncaught exceptions are a programming error and I want output that helps me as a programmer to fix that programming error. I don't care about "user-friendly data display" here. I think given the nature of hierarchical exceptions there is currently no generic way to show the exception type if the exception is at depth < 1 in the tree (for uncaught exceptions in Hspec I use the code at [1], which is better than using show but still not ideal). For this reason I *always* derive the Show instance if I define an exception type + I would prefer if Show instances for other exceptions would be derived, too (where possible). Would this proposal address this issue? How exactly? Could we just fix the (in my perspective) "broken" Show instances for standard exceptions instead? Cheers, Simon [1] https://github.com/hspec/hspec/blob/03651daf5b9eee4ca9e3c3941743519cda4768ab...

On Wed, Oct 29, 2014 at 4:22 AM, Simon Hengel
Hi Michael,
Personally, I think it will be nice to be able to quickly identify the constructor of the exception. Currently one has Google for the error message and hope for the best.
Thank you for pointing that out. As it happens, that's the exact conversation Chris and I had which led to this email ;).
Same thought here, one of my main complaints about the current state of exceptions is that the default exception handler gives you no hint about the type of uncaught exceptions.
For me uncaught exceptions are a programming error and I want output that helps me as a programmer to fix that programming error. I don't care about "user-friendly data display" here.
I think given the nature of hierarchical exceptions there is currently no generic way to show the exception type if the exception is at depth < 1 in the tree (for uncaught exceptions in Hspec I use the code at [1], which is better than using show but still not ideal).
For this reason I *always* derive the Show instance if I define an exception type + I would prefer if Show instances for other exceptions would be derived, too (where possible).
Would this proposal address this issue? How exactly? Could we just fix the (in my perspective) "broken" Show instances for standard exceptions instead?
We're coming from opposite ends on this one. I'm often writing user-facing applications, where a failure message of `FailedConection "www.example.com" 80` is bad, and "Unable to make a connection to www.example.com on port 80" is good. Both user-friendly and programmer-friendly display make sense, they're just different use cases. And currently, they're shoe-horned into the same `Show` instance. As long as we're all in agreement that I'm not making a real proposal, here's a solution to the problem: more methods! What about adding: displayException :: e -> String rawException :: e -> String -- meant to be the "serialized" version like derived Show instances verboseException :: e -> String -- include module the type is defined in, its package, data type, etc We can give all of these default implementations as well. The downside is that every possible usecase someone comes up with needs to go in Exception, which doesn't scale past a certain point. The question then becomes: have we already identified all of the use cases we care about? A completely different approach that might be better for your use case *and* might be useful in other cases would be to keep a stack of the `TypeRep`s we converted through when creating the SomeException. However, that would require a breaking change to SomeException, which I really *don't* want to propose. Michael

On Wed, Oct 29, 2014 at 10:33 AM, Michael Snoyman
A completely different approach that might be better for your use case *and* might be useful in other cases would be to keep a stack of the `TypeRep`s we converted through when creating the SomeException. However, that would require a breaking change to SomeException, which I really *don't* want to propose.
We already keep all the TypeReps, they just aren't generically accessible. If we added a function to the Exception class like typeRepStack :: a -> [TypeRep] it should work. A more-or-less sensible default is typeRepStack a = [typeOf a], which would work for all terminal exception types. A mid-level type in a hierarchy would need a different value though, something like typeRepStack se@(SomeException e) = typeOf se : typeRepStack e

+1 to having separate methods for Show-like and human-friendly displaying of exceptions. Not sure if we need rawException — just using Show superclass in this case seems appropriate. On 29/10/14 04:33, Michael Snoyman wrote:
On Wed, Oct 29, 2014 at 4:22 AM, Simon Hengel
wrote: Hi Michael,
Personally, I think it will be nice to be able to quickly identify the constructor of the exception. Currently one has Google for the error message and hope for the best.
Thank you for pointing that out. As it happens, that's the exact conversation Chris and I had which led to this email ;).
Same thought here, one of my main complaints about the current state of exceptions is that the default exception handler gives you no hint about the type of uncaught exceptions.
For me uncaught exceptions are a programming error and I want output that helps me as a programmer to fix that programming error. I don't care about "user-friendly data display" here.
I think given the nature of hierarchical exceptions there is currently no generic way to show the exception type if the exception is at depth < 1 in the tree (for uncaught exceptions in Hspec I use the code at [1], which is better than using show but still not ideal).
For this reason I *always* derive the Show instance if I define an exception type + I would prefer if Show instances for other exceptions would be derived, too (where possible).
Would this proposal address this issue? How exactly? Could we just fix the (in my perspective) "broken" Show instances for standard exceptions instead?
We're coming from opposite ends on this one. I'm often writing user-facing applications, where a failure message of `FailedConection "www.example.com" 80` is bad, and "Unable to make a connection to www.example.com on port 80" is good. Both user-friendly and programmer-friendly display make sense, they're just different use cases. And currently, they're shoe-horned into the same `Show` instance.
As long as we're all in agreement that I'm not making a real proposal, here's a solution to the problem: more methods! What about adding:
displayException :: e -> String rawException :: e -> String -- meant to be the "serialized" version like derived Show instances verboseException :: e -> String -- include module the type is defined in, its package, data type, etc
We can give all of these default implementations as well. The downside is that every possible usecase someone comes up with needs to go in Exception, which doesn't scale past a certain point. The question then becomes: have we already identified all of the use cases we care about?
A completely different approach that might be better for your use case *and* might be useful in other cases would be to keep a stack of the `TypeRep`s we converted through when creating the SomeException. However, that would require a breaking change to SomeException, which I really *don't* want to propose.
Michael

+1 to having separate methods for Show-like and human-friendly displaying of exceptions.
Yes, I agree. I've done a quick comparison on how Ruby/Python/Java convert exceptions to strings: https://github.com/sol/exceptions-by-language Note that in Ruby/Python there is a distinction between "getting a representation of a value" (inspect/repr) and "converting a value into a string" (to_s/str). In Haskell we only have show, which is akin to inspect/repr. All of them still use a different formatting in the default handler, so it may make still sense to make the full exception type accessible. But that could be a different discussion. Cheers, Simon

I guess I'm moderately sympathetic to the idea, although if I'm completely
honest it seems like a lot of make-work for little tangible benefit.
It would make more sense to me if there were also a push to make Read a
superclass of Exception, in which case Show should clearly be for
serialization (it is possible to make this work for
existentially-quantified data, but it would require manual instances).
It would make even more sense if Show were meant to be some sort of
user-readable string, and we used a different class (paired with Read) for
serialization. Unfortunately that ship sailed long ago.
John L.
On Wed, Oct 29, 2014 at 7:43 AM, Michael Snoyman
I don't want to make a format proposal yet, just open up discussion on an issue, and see how others feel about it.
As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
However, there's at least one use case in base which explicitly uses Show for non-serialization purposes: the Exception class. All instances of Exception are required to have an instance of Show, but there's no way to actually serialize exceptions generally[2]. So by construction and by practice, the Show instance for Exception is used exclusively for the latter two categories I mentioned (debug info and user-friendly data display).
As a result of that, it's quite common[3] to define a Show instance for exception types that is *not* serializable, but rather user friendly. This however seems to contradict what is accepted as good practice in general.
I have a possible solution that I'd like to propose as a strawman: add a new method to the Exception typeclass:
displayException :: e -> String displayException = show
The name is up for debate, but I chose `display` since it seems to already be used elsewhere for user-friendly output. Other possible choices are showException or prettyException. The default implementation will reuse the Show instance, so no user code will be broken by this[4].
In the short term, the only other change I'd recommend is that the default exception handler use `displayException` instead of `show` for printing uncaught exceptions. Longer term, after deprecation cycles, we could consider removing the Show superclass from Exception.
Again, this isn't a real proposal (yet), I'm more interested now in what people think about such a change.
Michael
[1] http://www.haskell.org/pipermail/libraries/2014-October/023957.html [2] Both due to how extensible exceptions work, and due to the lack of a Read superclass. [3] This discussion started when Chris Done and I were working with the tar package, which defines custom renderings for FormatError. I've implemented this same technique in some of my libraries, and I'm sure there are many other examples on Hackage. [4] Barring the standard issue of new identifiers clashing with identifiers defined locally.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On Tue, Oct 28, 2014 at 8:17 PM, John Lato
I guess I'm moderately sympathetic to the idea, although if I'm completely honest it seems like a lot of make-work for little tangible benefit.
It would make more sense to me if there were also a push to make Read a superclass of Exception, in which case Show should clearly be for serialization (it is possible to make this work for existentially-quantified data, but it would require manual instances).
It would make even more sense if Show were meant to be some sort of user-readable string, and we used a different class (paired with Read) for serialization. Unfortunately that ship sailed long ago.
Isn't there at least one prettyprinting package out there, with some sort of prettyprintable class? Could we steal it? David

On Wed, Oct 29, 2014 at 9:52 AM, Simon Hengel
It would make more sense to me if there were also a push to make Read a superclass of Exception
Considering that IOException can include a Handle, can this possibly work?
Cheers, Simon
What does it mean to try to make Show a serializer if the deserialization stage can't possibly work?

On Tue, Oct 28, 2014 at 6:43 PM, Michael Snoyman
As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
A bit off topic but, I think the semantics of Show/Read should actually be even stronger. Serializing to a String is a bit pointless -- things like Binary, Cereal, SafeCopy etc are much more suited for 'serialization'. It seems to me that Show and Read are really closer to ShowExpr and ReadExpr in many cases. The idea being that you can show a value, copy and paste that string into GHCi and get back your original value. For many show instances this holds true. Though clearly not all. I'd love to see: 1. Show/Read really be ShowExpr/ReadExpr 2. Binary 3. SafeCopy (like binary, but versioned with migration) 4. Pretty Of course, that opens the can of worms -- why not HTML instances, Markdown instances, etc. This is probably more a proposal for something like Idris where changes like this are still viable ;) - jeremy

Hi Michael, On 2014-10-29 at 00:43:55 +0100, Michael Snoyman wrote:
I don't want to make a format proposal yet, just open up discussion on an issue, and see how others feel about it.
As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
[...]
I have a possible solution that I'd like to propose as a strawman: add a new method to the Exception typeclass:
displayException :: e -> String displayException = show
As we're having the general problem of 'Show' being abused for pretty-printing, why not rather standardise on a pretty-show/printing typeclass that would not be limited to Exceptions? What am I missing? Cheers, hvr

On Wed, Oct 29, 2014 at 10:39 AM, Herbert Valerio Riedel
Hi Michael,
On 2014-10-29 at 00:43:55 +0100, Michael Snoyman wrote:
I don't want to make a format proposal yet, just open up discussion on an issue, and see how others feel about it.
As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
[...]
I have a possible solution that I'd like to propose as a strawman: add a new method to the Exception typeclass:
displayException :: e -> String displayException = show
As we're having the general problem of 'Show' being abused for pretty-printing, why not rather standardise on a pretty-show/printing typeclass that would not be limited to Exceptions? What am I missing?
The downside to that is that it introduces a breaking change, whereas this proposal does not. If we *do* want to standardize on a pretty-printing typeclass, I think the right way forward (though somewhat painful) is: Release X: Introduce the pretty-printing typeclass, add displayException with default implementation of Show, do not otherwise change Exception. Release X+1: Add new typeclass as a superclass of Exception. Release X+2: Switch default implementation of displayException to the pretty-show. Release X+3: Remove Show as a superclass. Maybe some of those steps can be combined, I'm not certain. Michael

As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read). Really? My instinct is otherwise: to use Show for human-readable display, and Binary for serialisation. Show/Read is a terribly inefficient serialisation format; as soon as you want to do it for real you end up with Binary anyway. And Show is already well established for human-readable purposes – that was one of its primary original purposes. Simon From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Michael Snoyman Sent: 28 October 2014 23:44 To: libraries; Christopher Done Subject: Discussion: adding displayException to Exception class I don't want to make a format proposal yet, just open up discussion on an issue, and see how others feel about it. As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read). However, there's at least one use case in base which explicitly uses Show for non-serialization purposes: the Exception class. All instances of Exception are required to have an instance of Show, but there's no way to actually serialize exceptions generally[2]. So by construction and by practice, the Show instance for Exception is used exclusively for the latter two categories I mentioned (debug info and user-friendly data display). As a result of that, it's quite common[3] to define a Show instance for exception types that is *not* serializable, but rather user friendly. This however seems to contradict what is accepted as good practice in general. I have a possible solution that I'd like to propose as a strawman: add a new method to the Exception typeclass: displayException :: e -> String displayException = show The name is up for debate, but I chose `display` since it seems to already be used elsewhere for user-friendly output. Other possible choices are showException or prettyException. The default implementation will reuse the Show instance, so no user code will be broken by this[4]. In the short term, the only other change I'd recommend is that the default exception handler use `displayException` instead of `show` for printing uncaught exceptions. Longer term, after deprecation cycles, we could consider removing the Show superclass from Exception. Again, this isn't a real proposal (yet), I'm more interested now in what people think about such a change. Michael [1] http://www.haskell.org/pipermail/libraries/2014-October/023957.html [2] Both due to how extensible exceptions work, and due to the lack of a Read superclass. [3] This discussion started when Chris Done and I were working with the tar package, which defines custom renderings for FormatError. I've implemented this same technique in some of my libraries, and I'm sure there are many other examples on Hackage. [4] Barring the standard issue of new identifiers clashing with identifiers defined locally.

On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones
As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
Really? My instinct is otherwise: *to use Show for human-readable display, and Binary for serialisation*. Show/Read is a terribly inefficient serialisation format; as soon as you want to do it for real you end up with Binary anyway. And Show is already well established for human-readable purposes – that was one of its primary original purposes.
Simon
My weak vote in that thread went towards Show for human-readable display, but there was some quite harsh objection to that position. In this thread too you can see people wanting a direct encoding of types which can be copy-pasted into a Haskell source file. Personally, I don't see much need for that, and especially given the new ability to essentially auto-derive Binary instances (via Generic), Show/Read serialization seems fairly pointless. Nonetheless, making a proposal that doesn't enforce a changed semantics on the Show typeclass seems like the path of least resistance. If others want to jump back into the previous topic and try to hammer down the ideal usage of the Show typeclass, I'm happy to participate in that discussion too. Michael

If people want Show to generate something that can be copy/pasted into a Haskell source file, that’s a legitimate position. But please let’s not call it “serialisation”!
So we have:
1. Serialisation (use Binary)
2. Copy-pasteable into Haskell source file, but not necessarily human-readable (Show)
3. Human readable (Display)
It’s clearly a library-design issue whether (2) and (3) are worth separating. More classes, more code, but perhaps more expressiveness. What does the core libraries committee think? Personally I don’t see (2) as particularly important, but my opinion counts for little since I’m not a library author.
Simon
From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Michael Snoyman
Sent: 29 October 2014 11:02
To: Simon Peyton Jones
Cc: libraries
Subject: Re: Discussion: adding displayException to Exception class
On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones

On Wed, Oct 29, 2014 at 1:18 PM, Simon Peyton Jones
If people want Show to generate something that can be copy/pasted into a Haskell source file, that’s a legitimate position. But please let’s not call it “serialisation”!
To be clear: people in this thread expressed the copy/paste concept. In the previous thread, serialization via Show/Read combination was definitely advocated. To hopefully flesh out all of the different positions I've seen expressed so far: 1. Express a valid Haskell expression for copy/paste reasons. 2. Express a valid Haskell expression to make it easy to determine the type of the exception thrown (even though that's not always enough information). 3. Express something that can be consumed by Read for easy serialization. 4. Print something which is meaningful to a Haskell developer. 5. Print something which would be meaningful to an end user. I agree completely that (3) should be handled by Binary (or equivalent: ToJSON/FromJSON, cereal, Storable...). And it seems like (1) and (4) should overlap perfectly, with one little exception: there are some things (like a Handle, IO action or function) which could be printed but not copy-pasted. (2) would likely be handled better via Typeable, possibly with some extra plumbing for cases like extensible exceptions. This is a great time for everyone to jump in with the use cases they care about that I've missed...
So we have:
1. Serialisation (use Binary)
2. Copy-pasteable into Haskell source file, but not necessarily human-readable (Show)
3. Human readable (Display)
It’s clearly a library-design issue whether (2) and (3) are worth separating. More classes, more code, but perhaps more expressiveness. What does the core libraries committee think? Personally I don’t see (2) as particularly important, but my opinion counts for little since I’m not a library author.
Simon
*From:* Libraries [mailto:libraries-bounces@haskell.org] *On Behalf Of *Michael Snoyman *Sent:* 29 October 2014 11:02 *To:* Simon Peyton Jones *Cc:* libraries *Subject:* Re: Discussion: adding displayException to Exception class
On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones < simonpj@microsoft.com> wrote:
As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
Really? My instinct is otherwise: *to use Show for human-readable display, and Binary for serialisation*. Show/Read is a terribly inefficient serialisation format; as soon as you want to do it for real you end up with Binary anyway. And Show is already well established for human-readable purposes – that was one of its primary original purposes.
Simon
My weak vote in that thread went towards Show for human-readable display, but there was some quite harsh objection to that position. In this thread too you can see people wanting a direct encoding of types which can be copy-pasted into a Haskell source file. Personally, I don't see much need for that, and especially given the new ability to essentially auto-derive Binary instances (via Generic), Show/Read serialization seems fairly pointless.
Nonetheless, making a proposal that doesn't enforce a changed semantics on the Show typeclass seems like the path of least resistance. If others want to jump back into the previous topic and try to hammer down the ideal usage of the Show typeclass, I'm happy to participate in that discussion too.
Michael

2014-10-29 12:25 GMT+01:00 Michael Snoyman
[possible use cases for Show] 1. Express a valid Haskell expression for copy/paste reasons. 2. Express a valid Haskell expression to make it easy to determine the type of the exception thrown (even though that's not always enough information). 3. Express something that can be consumed by Read for easy serialization. 4. Print something which is meaningful to a Haskell developer. 5. Print something which would be meaningful to an end user.
If we enter this discussion, I think we should keep in mind how some of these uses are encouraged by the infrastructure. Specifically: * the fact that GHCi uses Show for printing result values, counts (at least for me) as an implicit vote for use case (4) * the fact that deriving Show is directly supported by the compiler (contrary to Binary, for example) making it easier to use Show than more appropriate alternatives. If we think Show is the wrong solution for serialisation, then maybe the compiler should provide equivalent support for a more adequate solution, for example? Regards, Dominique

On Wed, Oct 29, 2014 at 1:43 PM, Dominique Devriese < dominique.devriese@cs.kuleuven.be> wrote:
2014-10-29 12:25 GMT+01:00 Michael Snoyman
: [possible use cases for Show] 1. Express a valid Haskell expression for copy/paste reasons. 2. Express a valid Haskell expression to make it easy to determine the type of the exception thrown (even though that's not always enough information). 3. Express something that can be consumed by Read for easy serialization. 4. Print something which is meaningful to a Haskell developer. 5. Print something which would be meaningful to an end user.
If we enter this discussion, I think we should keep in mind how some of these uses are encouraged by the infrastructure. Specifically: * the fact that GHCi uses Show for printing result values, counts (at least for me) as an implicit vote for use case (4) * the fact that deriving Show is directly supported by the compiler (contrary to Binary, for example) making it easier to use Show than more appropriate alternatives. If we think Show is the wrong solution for serialisation, then maybe the compiler should provide equivalent support for a more adequate solution, for example?
Regards, Dominique
Those are good points. For your first one: that's why my quasi-proposal stated that GHC's default exception handler should switch over to using the new pretty-printed exception method (since I'd like (5) to be the target in that case). Regarding your second point: Generic-based instances go a long way towards solving that problem, and- unless I'm mistaken- starting with GHC 7.10 it will be possible to do something like: data Foo = ... deriving (Generic, Binary, ToJSON, FromJSON) Michael

| * the fact that deriving Show is directly supported by the compiler | (contrary to Binary, for example) making it easier to use Show than | more appropriate alternatives. If we think Show is the wrong solution | for serialisation, then maybe the compiler should provide equivalent | support for a more adequate solution, for example? yes, that's quite possible.

Agreed!
I think there has been general consensus that when possible, Show
should generate valid Haskell code. Suppose that you want to
reproduce some bug where a specific set of functions are suspected.
If there arguments are 'Show' instances, then you can output
invocations of these functions to a file. This file can now be used
as an executable, minimizable reproduction of the bug!
Honestly, I think 'Read' isn't all that important except for things
like parsing numbers, very small applications. and prototypes. In
practical code, you either end up using a serialization like binary or
aeson, or writing your own pretty printer / parser. I'd rather have
the property that 'show' results in code than the property that "read
. show === id" (but certainly this is a nice property to have!).
Michael
On Wed, Oct 29, 2014 at 4:25 AM, Michael Snoyman
On Wed, Oct 29, 2014 at 1:18 PM, Simon Peyton Jones
wrote: If people want Show to generate something that can be copy/pasted into a Haskell source file, that’s a legitimate position. But please let’s not call it “serialisation”!
To be clear: people in this thread expressed the copy/paste concept. In the previous thread, serialization via Show/Read combination was definitely advocated. To hopefully flesh out all of the different positions I've seen expressed so far:
1. Express a valid Haskell expression for copy/paste reasons. 2. Express a valid Haskell expression to make it easy to determine the type of the exception thrown (even though that's not always enough information). 3. Express something that can be consumed by Read for easy serialization. 4. Print something which is meaningful to a Haskell developer. 5. Print something which would be meaningful to an end user.
I agree completely that (3) should be handled by Binary (or equivalent: ToJSON/FromJSON, cereal, Storable...). And it seems like (1) and (4) should overlap perfectly, with one little exception: there are some things (like a Handle, IO action or function) which could be printed but not copy-pasted. (2) would likely be handled better via Typeable, possibly with some extra plumbing for cases like extensible exceptions.
This is a great time for everyone to jump in with the use cases they care about that I've missed...
So we have:
1. Serialisation (use Binary)
2. Copy-pasteable into Haskell source file, but not necessarily human-readable (Show)
3. Human readable (Display)
It’s clearly a library-design issue whether (2) and (3) are worth separating. More classes, more code, but perhaps more expressiveness. What does the core libraries committee think? Personally I don’t see (2) as particularly important, but my opinion counts for little since I’m not a library author.
Simon
From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Michael Snoyman Sent: 29 October 2014 11:02 To: Simon Peyton Jones Cc: libraries Subject: Re: Discussion: adding displayException to Exception class
On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones
wrote: As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
Really? My instinct is otherwise: to use Show for human-readable display, and Binary for serialisation. Show/Read is a terribly inefficient serialisation format; as soon as you want to do it for real you end up with Binary anyway. And Show is already well established for human-readable purposes – that was one of its primary original purposes.
Simon
My weak vote in that thread went towards Show for human-readable display, but there was some quite harsh objection to that position. In this thread too you can see people wanting a direct encoding of types which can be copy-pasted into a Haskell source file. Personally, I don't see much need for that, and especially given the new ability to essentially auto-derive Binary instances (via Generic), Show/Read serialization seems fairly pointless.
Nonetheless, making a proposal that doesn't enforce a changed semantics on the Show typeclass seems like the path of least resistance. If others want to jump back into the previous topic and try to hammer down the ideal usage of the Show typeclass, I'm happy to participate in that discussion too.
Michael
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I could definitely see adding a separate displayException method to
Exception.
+1 there.
Removing Show as a superclass however is something we'd have to check, its
the kind of thing where it'd silently affect some code that was just
accepting the exception and printing it in a manner that could be worked
around by using a pair of constraints, just like the change breaking up Num
that Ian put through a few years back.
If that is something folks *really* want to do, we could probably get there.
If we did then you'd probably want
class Typeable a => Exception a where
...
displayException :: a -> String
default displayException :: Show a => a -> String
displayException = show
which would let most of the existing code around it work, and only break
the code that takes an exception blindly and prints it.
Adding displayException strikes me as easy, and zero-pain.
Removing Show on the other hand is something I'm somewhat less sanguine
about, but not either for or against.
-Edward
On Wed, Oct 29, 2014 at 9:56 AM, Michael Sloan
Agreed!
I think there has been general consensus that when possible, Show should generate valid Haskell code. Suppose that you want to reproduce some bug where a specific set of functions are suspected. If there arguments are 'Show' instances, then you can output invocations of these functions to a file. This file can now be used as an executable, minimizable reproduction of the bug!
Honestly, I think 'Read' isn't all that important except for things like parsing numbers, very small applications. and prototypes. In practical code, you either end up using a serialization like binary or aeson, or writing your own pretty printer / parser. I'd rather have the property that 'show' results in code than the property that "read . show === id" (but certainly this is a nice property to have!).
Michael
On Wed, Oct 29, 2014 at 4:25 AM, Michael Snoyman
wrote: On Wed, Oct 29, 2014 at 1:18 PM, Simon Peyton Jones <
wrote:
If people want Show to generate something that can be copy/pasted into a Haskell source file, that’s a legitimate position. But please let’s not call it “serialisation”!
To be clear: people in this thread expressed the copy/paste concept. In
previous thread, serialization via Show/Read combination was definitely advocated. To hopefully flesh out all of the different positions I've seen expressed so far:
1. Express a valid Haskell expression for copy/paste reasons. 2. Express a valid Haskell expression to make it easy to determine the type of the exception thrown (even though that's not always enough information). 3. Express something that can be consumed by Read for easy serialization. 4. Print something which is meaningful to a Haskell developer. 5. Print something which would be meaningful to an end user.
I agree completely that (3) should be handled by Binary (or equivalent: ToJSON/FromJSON, cereal, Storable...). And it seems like (1) and (4) should overlap perfectly, with one little exception: there are some things (like a Handle, IO action or function) which could be printed but not copy-pasted. (2) would likely be handled better via Typeable, possibly with some extra plumbing for cases like extensible exceptions.
This is a great time for everyone to jump in with the use cases they care about that I've missed...
So we have:
1. Serialisation (use Binary)
2. Copy-pasteable into Haskell source file, but not necessarily human-readable (Show)
3. Human readable (Display)
It’s clearly a library-design issue whether (2) and (3) are worth separating. More classes, more code, but perhaps more expressiveness. What does the core libraries committee think? Personally I don’t see
(2) as
particularly important, but my opinion counts for little since I’m not a library author.
Simon
From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Michael Snoyman Sent: 29 October 2014 11:02 To: Simon Peyton Jones Cc: libraries Subject: Re: Discussion: adding displayException to Exception class
On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones
wrote: As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
Really? My instinct is otherwise: to use Show for human-readable display, and Binary for serialisation. Show/Read is a terribly inefficient serialisation format; as soon as you want to do it for real you end up with Binary anyway. And Show is already well established for human-readable purposes – that was one of its primary original purposes.
Simon
My weak vote in that thread went towards Show for human-readable display, but there was some quite harsh objection to that position. In this
simonpj@microsoft.com> the thread
too you can see people wanting a direct encoding of types which can be copy-pasted into a Haskell source file. Personally, I don't see much need for that, and especially given the new ability to essentially auto-derive Binary instances (via Generic), Show/Read serialization seems fairly pointless.
Nonetheless, making a proposal that doesn't enforce a changed semantics on the Show typeclass seems like the path of least resistance. If others want to jump back into the previous topic and try to hammer down the ideal usage of the Show typeclass, I'm happy to participate in that discussion too.
Michael
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- You received this message because you are subscribed to the Google Groups "haskell-core-libraries" group. To unsubscribe from this group and stop receiving emails from it, send an email to haskell-core-libraries+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout.

I’m a bit late but I thought I’d chime in as the Show situation is delicate for me. Pretty much as you said, I’d categorize printing (of general Haskell values) by the audience: Users Programmers Programs Here’s an example of each: "The tar archive is corrupt (truncated)." :: String TruncatedArchive :: FormatError "\1" :: ByteString I would like to add that for the kind targeting programmers, it’s not that I would necessarily like to be able to copy/paste the printing of something into my source code. I use Show for debugging. Rather, I want to know what the value is. So I need the constructor and any fields in it. I think it’s essential for debugging, and I feel spoiled in Haskell that most types have a reasonable Show instance that shows the structure of a value for me. But often, cases like this, it’s just a human-readable string which, as a programmer, is very unhelpful to me. So we already have standard ways of doing each of these, of course: We have things like Doc for pretty printing for users. We have Show for printing the structure of a value. We have binary/cereal/aeson for serializing. The issue is that pretty printing is not very helpful for me. For example, working with the GHC API is particularly difficult because almost all types do not have a Show instance. This breaks my normal Haskell development workflow, which is that I’ll run a function and print out the values. For example, say I’m working with Core and I have an Expr type. I’m pattern matching on the AST constructor by constructor. I generate some core, and I want to see what constructor is used where. If I use the Outputable class to print the Core, all I get is a pretty printed concrete syntax. Pretty, but not useful to me. How can I get that information? So I end up defining a gshow :: Data => a -> Show function, just to see exactly the structure of the data I’m working with, which is what show normally gives me. I think the case of “being able to copy/paste it as source code” is a little bit out of place given things like fromList [(1,'a')] for a Map Int Char and Handle {<1>} (or whatever it was for the Handle type). The Handle’s Show instance is, to my mind, a perfectly legitimate instance for telling you what this value is. It contains an fd and it prints it. It has no Read instance, there’s no pretense of being “serializable” or “copy/pastable”. I have the same issues with exceptions, as noted by Michael. I’d like to know as a programmer what the exception is, as a Haskell value. Separately a way of printing exceptions for users would be welcome too and in the case of web/UI apps it seems very useful.

I just like to add that I find it very useful to be able to just copy the output of show to ghci. As an example, I wrote an AI that used a game tree as state. When debugging, I can just print this tree after each turn using show and then paste it to ghci to simulate the game starting from the state at that turn. If Show was not valid Haskell code, I would have had to write a serializer a d deserializer first, which isn't so easy to do for a tree structure. -- Benno

On Wed, Oct 29, 2014 at 10:20 AM, Christopher Done
Rather, I want to know what the value is. So I need the constructor and any fields in it. I think it’s essential for debugging, and I feel spoiled in Haskell that most types have a reasonable Show instance that shows the structure of a value for me.
I think the case of “being able to copy/paste it as source code” is a little bit out of place given things like fromList [(1,'a')] for a Map Int Char and Handle {<1>} (or whatever it was for the Handle type). The Handle’s Show instance is, to my mind, a perfectly legitimate instance for telling you what this value is. It contains an fd and it prints it. It has no Read instance, there’s no pretense of being “serializable” or “copy/pastable”.
It is definitely the case that not all useful values can be shown as valid Haskell code. But in the cases where they can -- I think it is useful even if you never actually copy & paste. If the value is shown as valid Haskell then you truly have all the information you could possibly need about that value. And you get it in a syntax that you are already familiar with -- so there is no need to learn another way of reading things. I'm curious about your, fromList [(1, 'a')], example. That seems exactly like a case where the Show instance is providing you with valid Haskell code to recreate the value aside from issue that fromList could be ambiguous. If I had to create some rules for Show it would probably involve: 1. if it is possible to write a Read instance, then the Show instance should create valid Haskell code 2. if a Read instance is not possible, then the Show instance should come as close to valid Haskell as possible while yielding the maximum amount of information available. It seems like both Map and Handle would meet those requires. Map has Read/Show instances and the String format is valid Haskell. For Handle, a Read instance is not possible, but it does give you as much information as possible. I believe 'deriving (Read, Show)' naturally meets requirement #1 as long as any Read/Show instances it depends on also meet requirement #1 ? - jeremy

Well, I think fromList [(1, 'a')] is kind of unhelpful: 1. It almost never is a straight copy/paste, you will have to go and add M. to the fromList. 2. It doesn’t actually tell you what you’re looking at: (fromList [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')] ,fromList [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')] ,fromList [1,2,3,4,5] ,fromList [1,2,3,4,5]) What are you looking at? Answer:
import qualified Data.Map as M import qualified Data.HashMap.Strict as HM import qualified Data.Vector as V import qualified Data.Vector as S (M.fromList (zip [0..5] ['a'..]) ,HM.fromList (zip [0..5] ['a'..]) ,S.fromList [1..5] ,V.fromList [1..5])
It’s true that numbers (Int/Integer) get a free pass on this, but I consider those an exception. I’d prefer (if we’re restricting ourselves to strings) something like Map [(0,'a'),(1,'b'),(2,'c')] StrictHashMap [(0,'a'),(1,'b'),(2,'c')] Set [0,1,2,3,4,5]Vector [0,1,2,3,4,5] But this is not the status quo and I don’t see it changing soon. People are set on the “looks like code” idea more than “describe the data structure”. ------------------------------ Digression: While we’re on the subject, I’d like to be able to convert any Haskell value to a Presentation http://hackage.haskell.org/package/present-1.1/docs/Present-Types.html which IDEs and browsers can use to trivially expand data structures lazily, like this: λ> present (fromJust (fromList [0])) [1..5]Just (List "[Integer]" [("Integer",@0→0),("[Integer]",@0→1)]) λ> present (fromJust (fromList [0,0])) (T.pack "hi")Just (Char "Char" "'h'") λ> present (fromJust (fromList [0,1])) (T.pack "hi")Just (String "Text" [("Char",@0→1→0),("Text",@0→1→1)]) λ> present (fromJust (fromList [0])) "hello!"Just (String "String" [("Char",@0→0),("String",@0→1)]) λ> present (fromJust (fromList [0,0])) "hello!"Just (Char "Char" "'h'") λ> present (fromJust (fromList [0,1,0])) "hello!"Just (Char "Char" "'e'") Video of Emacs taking advantage of this output. https://www.youtube.com/watch?v=oJhIvHtflbI And to be able to choose *how to present* the structure. E.g. if I wanted, I could present a Set like: {0 1 2 3 4 5} and a Map like: { 0 => 'a', 1 => 'b', 2 => 'c' } and, let’s say I add a Tree constructor to the Presentation type, i.e. a known “tree-ish” structure, then I can render a Data.Tree like: {0 1 2 3} / \ {4 5 6} {7 8 9} … … Where the … is an expansion thing to click. Because Presentation contains type information, you can hover your mouse or whatever to inspect the types of things. But making this work in the general sense has been hard: Show is not parseable, many data types in real projects are not instances of Data (and types like Text and Vector have bogus instances). I believe my only recourse will be using the GHC API to inspect data types or template-haskell’s reify in an effort to cross module encapsulation. Now that Typeable is not user-definable, one cannot use the derive http://hackage.haskell.org/package/derive package, either. I think the :sprint/:print of GHCi is sort of there, but using it would be more hacky — it would be better to hook into whatever API is used to produce that feature in GHC and spit out a Presentation. In general, it seems the current Haskell state of affairs makes it tricky to just print a value and expand it incrementally in the same way that you can in Common Lisp or JavaScript.

1. Serialisation (use Binary) 2. Copy-pasteable into Haskell source file, but not necessarily human-readable (Show) 3. Human readable (Display)
I agree a lot to this. While for Simon 2 doesn't seem to be useful, Show representing the Haskell value and its structure as much as possible is super useful when debugging business logic code, especially when it was written by other people years ago. It's rarely done, but when you actually do use ghci with break points, Show is a very useful (and necessary) tool to see what's in your values, and you wish every type had a Show instance - even better if it's a derived one. IMO, using Show for pretty printing defeats a lot of the above purpose, and thus I welcome any effort to separate Show and Display things (so +1). Yes, sometimes the Show instances aren't as nice as we would like them to be (e.g. fromList for Sets as Chris mentioned), but despite these unhappy cases, the debugging/programmer oriented nature of Show seems fundamental to me. There seems to be full consensus that Show (and any String based functionality) isn't a good idea for "serialisation as part of the program functionality". We just have to be careful to distinguish this from "serialisation for the programmer/debugging", since when people say just "serialisation" they can mean either. Regarding Jeremy's proposed rules for Read/Show, I would put them in different order: 1. the Show instance should always come as close to valid Haskell as possible 2. if it is possible to write a Read instance, write (best derive) one, otherwise don't (e.g. if your thing contains IORefs)

My experience is that whenever someone writes a "helpful" Show instance it
winds up anything but.
Why?
What happens when you print a list of them, or they occur deeper in a
larger structure?
Invariably I wind up with things like a bag of your exceptions in an async
exception wrapper or someone's position type in my data structure -- I
first noticed this when I was working with parsec.
I'd stick source positions in my data types, but Parsec was helpful:
instance Show SourcePos where show (SourcePos name line column) |
null name = showLineColumn | otherwise = "\"" ++ name ++ "\" " ++
showLineColumn where showLineColumn = "(line " ++ show line
++ ", column " ++ show column ++
")"
.. and with that now users can't made hide nor hair out of syntax tree
terms, etc.
"Helpful" Show instances are not compositional.
-Edward
On Wed, Oct 29, 2014 at 9:22 PM, Niklas Hambüchen
1. Serialisation (use Binary) 2. Copy-pasteable into Haskell source file, but not necessarily human-readable (Show) 3. Human readable (Display)
I agree a lot to this.
While for Simon 2 doesn't seem to be useful, Show representing the Haskell value and its structure as much as possible is super useful when debugging business logic code, especially when it was written by other people years ago.
It's rarely done, but when you actually do use ghci with break points, Show is a very useful (and necessary) tool to see what's in your values, and you wish every type had a Show instance - even better if it's a derived one.
IMO, using Show for pretty printing defeats a lot of the above purpose, and thus I welcome any effort to separate Show and Display things (so +1).
Yes, sometimes the Show instances aren't as nice as we would like them to be (e.g. fromList for Sets as Chris mentioned), but despite these unhappy cases, the debugging/programmer oriented nature of Show seems fundamental to me.
There seems to be full consensus that Show (and any String based functionality) isn't a good idea for "serialisation as part of the program functionality". We just have to be careful to distinguish this from "serialisation for the programmer/debugging", since when people say just "serialisation" they can mean either.
Regarding Jeremy's proposed rules for Read/Show, I would put them in different order:
1. the Show instance should always come as close to valid Haskell as possible 2. if it is possible to write a Read instance, write (best derive) one, otherwise don't (e.g. if your thing contains IORefs)
-- You received this message because you are subscribed to the Google Groups "haskell-core-libraries" group. To unsubscribe from this group and stop receiving emails from it, send an email to haskell-core-libraries+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout.

Quoting Christopher Done (2014-10-29 23:07:54)
Well, I think fromList [(1, 'a')] is kind of unhelpful:
1. It almost never is a straight copy/paste, you will have to go and add M. to the fromList.
Chris Done is hinting at a shortcoming to the usage of `Show` in the sense of Jeremy Shaw's ShowExpr: It does not support qualified imports at all. It might be nice to append a `My.Module` to each function in `show`'s output whenever a module is meant to be imported qualified. There might be some heuristics on when that's the case (hiding parts of `Prelude`), but that's certainly something only the compiler (or TH) can do. Cheers, tobias florek

On 30 October 2014 11:00, Tobias Florek haskell@ibotty.net http://mailto:haskell@ibotty.net wrote: Quoting Christopher Done (2014-10-29 23:07:54) Well, I think fromList [(1, ‘a’)] is kind of unhelpful: 1. It almost never is a straight copy/paste, you will have to go and add M. to the fromList. Chris Done is hinting at a shortcoming to the usage of Show in the sense of Jeremy Shaw’s ShowExpr: It does not support qualified imports at all. It might be nice to append a My.Module to each function in show‘s output whenever a module is meant to be imported qualified. There might be some heuristics on when that’s the case (hiding parts of Prelude), but that’s certainly something only the compiler (or TH) can do. Technically Data.Typeable has this information:
tyConModule (typeRepTyCon (typeOf (S.fromList [()])))"Data.Set.Base" tyConName (typeRepTyCon (typeOf (S.fromList [()])))"Set" tyConPackage (typeRepTyCon (typeOf (S.fromList [()])))"containers-0.5.5.1"
Data.Generics.Text http://hackage.haskell.org/package/syb-0.3.6/docs/Data-Generics-Text.html can give a more structured output (though it doesn’t), but then there lies the issue:
gshow TruncatedArchive
<interactive>:25:1: No instance for (Data FormatError) arising from a use of ‘gshow’ In the expression: gshow TruncatedArchive In an equation for ‘it’: it = gshow TruncatedArchive Hardly any data types are actually instances of Data. And the ones that are can often be bogus, even “standard” ones like Data.Vector and Data.Text:
gshow (V.fromList [1]) "(*** Exception: toConstr
gshow (T.pack "x") "(*** Exception: Data.Text.Text.toConstr
So while Data.Data could be a perfect solution for printing, at the moment it can’t be relied upon to exist.

As you notice, the show functions for collections are implemented wrongly, they should print Fully.Qualified.Module.fromList [(key,value),...] High time to repent now and not sin again. Positive example: https://hackage.haskell.org/package/Agda-2.4.0/docs/src/Agda-Utils-BiMap.htm... On 29.10.2014 23:07, Christopher Done wrote:
Well, I think |fromList [(1, 'a')]| is kind of unhelpful:
1. It almost never is a straight copy/paste, you will have to go and add M. to the fromList. 2. It doesn’t actually tell you what you’re looking at:
|(fromList [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')] ,fromList [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')] ,fromList [1,2,3,4,5] ,fromList [1,2,3,4,5]) |
What are you looking at?
Answer:
|>import qualified Data.Mapas M
import qualified Data.HashMap.Strictas HM import qualified Data.Vectoras V import qualified Data.Vectoras S (M.fromList (zip [0..5] ['a'..]) ,HM.fromList (zip [0..5] ['a'..]) ,S.fromList [1..5] ,V.fromList [1..5]) |
It’s true that numbers (|Int|/|Integer|) get a free pass on this, but I consider those an exception. I’d prefer (if we’re restricting ourselves to strings) something like
|Map [(0,'a'),(1,'b'),(2,'c')] StrictHashMap [(0,'a'),(1,'b'),(2,'c')] Set [0,1,2,3,4,5] Vector [0,1,2,3,4,5] |
But this is not the status quo and I don’t see it changing soon. People are set on the “looks like code” idea more than “describe the data structure”.
------------------------------------------------------------------------
Digression:
While we’re on the subject, I’d like to be able to convert any Haskell value to a Presentation http://hackage.haskell.org/package/present-1.1/docs/Present-Types.html which IDEs and browsers can use to trivially expand data structures lazily, like this:
|λ> present (fromJust (fromList [0])) [1..5] Just (List "[Integer]" [("Integer",@0→0),("[Integer]",@0→1)]) λ> present (fromJust (fromList [0,0])) (T.pack"hi") Just (Char "Char" "'h'") λ> present (fromJust (fromList [0,1])) (T.pack"hi") Just (String "Text" [("Char",@0→1→0),("Text",@0→1→1)]) λ> present (fromJust (fromList [0]))"hello!" Just (String "String" [("Char",@0→0),("String",@0→1)]) λ> present (fromJust (fromList [0,0]))"hello!" Just (Char "Char" "'h'") λ> present (fromJust (fromList [0,1,0]))"hello!" Just (Char "Char" "'e'") |
Video of Emacs taking advantage of this output. https://www.youtube.com/watch?v=oJhIvHtflbI
And to be able to choose /how to present/ the structure. E.g. if I wanted, I could present a |Set| like:
|{0 1 2 3 4 5} |
and a |Map| like:
|{0 => 'a',1 => 'b',2 => 'c' } |
and, let’s say I add a |Tree| constructor to the |Presentation| type, i.e. a known “tree-ish” structure, then I can render a |Data.Tree| like:
| {0 1 2 3} / \ {4 5 6} {7 8 9} … … |
Where the |…| is an expansion thing to click. Because |Presentation| contains type information, you can hover your mouse or whatever to inspect the types of things.
But making this work in the general sense has been hard: Show is not parseable, many data types in real projects are not instances of Data (and types like Text and Vector have bogus instances). I believe my only recourse will be using the GHC API to inspect data types or template-haskell’s |reify| in an effort to cross module encapsulation. Now that Typeable is not user-definable, one cannot use the derive http://hackage.haskell.org/package/derive package, either. I think the |:sprint|/|:print| of GHCi is sort of there, but using it would be more hacky — it would be better to hook into whatever API is used to produce that feature in GHC and spit out a |Presentation|.
In general, it seems the current Haskell state of affairs makes it tricky to just print a value and expand it incrementally in the same way that you can in Common Lisp or JavaScript.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel@gu.se http://www2.tcs.ifi.lmu.de/~abel/

On 29.10.2014 12:18, Simon Peyton Jones wrote:
1.Serialisation (use Binary)
2.Copy-pasteable into Haskell source file, but not necessarily human-readable (Show)
3.Human readable (Display)
+1. These should all be separate, and we want a standard class for 3. "Display" seems to be a good name.
It’s clearly a library-design issue whether (2) and (3) are worth separating. More classes, more code, but perhaps more expressiveness. What does the core libraries committee think? Personally I don’t see (2) as particularly important, but my opinion counts for little since I’m not a library author.
Simon
*From:*Libraries [mailto:libraries-bounces@haskell.org] *On Behalf Of *Michael Snoyman *Sent:* 29 October 2014 11:02 *To:* Simon Peyton Jones *Cc:* libraries *Subject:* Re: Discussion: adding displayException to Exception class
On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones
mailto:simonpj@microsoft.com> wrote: As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
Really? My instinct is otherwise: *to use Show for human-readable display, and Binary for serialisation*. Show/Read is a terribly inefficient serialisation format; as soon as you want to do it for real you end up with Binary anyway. And Show is already well established for human-readable purposes – that was one of its primary original purposes.
Simon
My weak vote in that thread went towards Show for human-readable display, but there was some quite harsh objection to that position. In this thread too you can see people wanting a direct encoding of types which can be copy-pasted into a Haskell source file. Personally, I don't see much need for that, and especially given the new ability to essentially auto-derive Binary instances (via Generic), Show/Read serialization seems fairly pointless.
Nonetheless, making a proposal that doesn't enforce a changed semantics on the Show typeclass seems like the path of least resistance. If others want to jump back into the previous topic and try to hammer down the ideal usage of the Show typeclass, I'm happy to participate in that discussion too.
Michael
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
-- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel@gu.se http://www2.tcs.ifi.lmu.de/~abel/

I strongly agree with this proposal. It's nice to encode in the API that these error messages are expected to be displayed to users of applications, and not just developers. A particularly blatant example of this going wrong is in System.IO.Error, where you get this delightful behavior:
fail "brain exploded" *** Exception: user error (brain exploded)
The poor user is going to think that the program is accusing them of
having an exploded brain. Similarly:
Prelude> Just x <- return Nothing
*** Exception: user error (Pattern match failure in do expression at
<interactive>:5:1-6)
This is clearly a programming error, not a "user error".
In order to encourage thought about application user consumption of
error messages, I think a couple warnings ought to be added:
1) A warning when the definition of "displayException" is omitted.
This would be a new GHC warning pragma, which could potentially re-use
the syntax from MINIMAL, to make the warning more flexible. It would
recommend that they write a custom implementation and consider how the
error will look to application users (though, not at the cost of
informativeness to developers). It could also warn about the pending
removal of the Show superclass and default implementation of
"displayException", if that was decided on (I think it should be!)
2) A warning for all uses of "show :: a -> String" when in a context
where "Exception a" holds. This would also be a new variety of
warning, potentially hardcoded in GHC, but ideally generalized. It's
important to have this warning because users might still be using
'show' when 'displayException' is more appropriate. How to suppress
such warnings when you really do want 'show'? A "showException =
show" function would work for that.
A warning when "Show a" is used when in a context where "Exception a"
holds would catch additional cases. However, it would be much more
spammy and unclear how to suppress it. I think the warning describe
above is still worth it, though, even if it's just to catch situations
where 'show' is being used on a nested exception value in order to
implement the 'displayException' method (or the instance of Show that
relies on).
This would also ease the pain of removing Show as a superclass
constraint. I imagine this removal would break more code than the
removal of Eq / Show as superclasses of Num.
Michael
On Tue, Oct 28, 2014 at 4:43 PM, Michael Snoyman
I don't want to make a format proposal yet, just open up discussion on an issue, and see how others feel about it.
As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read).
However, there's at least one use case in base which explicitly uses Show for non-serialization purposes: the Exception class. All instances of Exception are required to have an instance of Show, but there's no way to actually serialize exceptions generally[2]. So by construction and by practice, the Show instance for Exception is used exclusively for the latter two categories I mentioned (debug info and user-friendly data display).
As a result of that, it's quite common[3] to define a Show instance for exception types that is *not* serializable, but rather user friendly. This however seems to contradict what is accepted as good practice in general.
I have a possible solution that I'd like to propose as a strawman: add a new method to the Exception typeclass:
displayException :: e -> String displayException = show
The name is up for debate, but I chose `display` since it seems to already be used elsewhere for user-friendly output. Other possible choices are showException or prettyException. The default implementation will reuse the Show instance, so no user code will be broken by this[4].
In the short term, the only other change I'd recommend is that the default exception handler use `displayException` instead of `show` for printing uncaught exceptions. Longer term, after deprecation cycles, we could consider removing the Show superclass from Exception.
Again, this isn't a real proposal (yet), I'm more interested now in what people think about such a change.
Michael
[1] http://www.haskell.org/pipermail/libraries/2014-October/023957.html [2] Both due to how extensible exceptions work, and due to the lack of a Read superclass. [3] This discussion started when Chris Done and I were working with the tar package, which defines custom renderings for FormatError. I've implemented this same technique in some of my libraries, and I'm sure there are many other examples on Hackage. [4] Barring the standard issue of new identifiers clashing with identifiers defined locally.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
participants (17)
-
Andreas Abel
-
Benno Fünfstück
-
Christopher Done
-
David Feuer
-
Dominique Devriese
-
Edward Kmett
-
Felipe Lessa
-
Herbert Valerio Riedel
-
Jeremy Shaw
-
John Lato
-
Michael Sloan
-
Michael Snoyman
-
Niklas Hambüchen
-
Roman Cheplyaka
-
Simon Hengel
-
Simon Peyton Jones
-
Tobias Florek