From gershomb at gmail.com Wed Apr 1 04:22:24 2015 From: gershomb at gmail.com (Gershom B) Date: Wed, 1 Apr 2015 00:22:24 -0400 Subject: An Easy Solution to PVP Bounds and Cabal Hell Message-ID: Recently there has been some discussion about how we can fix the problem of ?Cabal Hell?. Some people advocate restrictive upper bounds, to prevent packages from being broken by new updates. Some other people point out that too-restrictive bounds can lead to bad install plans, since some packages might want newer versions of some dependencies, and others older versions. Still other people say that we can _retroactively_ fix upper bounds (in either direction) by modifying cabal files using the new features in Hackage. Some people think this is a terrible idea because it looks like we are mutating things, and this confuses hashes. In turn, these people support either nix or a nix-like approach by which packages have hashes that encompass the full versions of all their transitive dependencies. With that in hand, we can cache builds and mix-and-match to build the precise environment we want for each package while reducing redundant computation. However, the cache of all the various binary combinations may still grow large! And none of this fully begins to address the dreaded ?diamond dependency? problem. Here is a chart of some such solutions: http://www.well-typed.com/blog/aux/images/cabal-hell/cabal-hell-solutions.png One way to look at a particular build is in an n-dimensional state space (of the Hilbert sort) determined by all its dependencies, not least the compiler itself. The solver acts as a particle traversing this space. But this description is too simple. Our state of dependencies and constraints itself varies and grows over time. So another approach is to think of the dependencies as a transitive graph, where each node may vary along a time axis, and as they slide along the axis, this in turn affects their children. We now have not just one Hilbert space, but a collection of them related by branching trees as authors locally modify the dependencies of their packages. If we keep this simple model in mind, it is easy to see why everyone is always having these debates. Some people want to fix the graph, and others want to simplify it. Some people want an immutable store, and some people want to rebase. But we can?t ?really? rebase in our current model. Bearing in mind our model of a space-time continuum of hackage dependences, the solution emerges ? enforce immutability, but allow retroactive mutation. For instance, suppose Fred tries to install package Foo on Friday evening, but discovers that it depends on version 1.0 of Bar (released the previous Friday) that in turn depends on version 0.5 of Baz but Foo also depends on version 0.8 of Baz. So Fred branches Bar and changes the dependency, which in turn informs Betty, that there is also a 1.0 of Bar with different dependencies and we have forked our package timeline. On getting this message on Monday, Betty can merge by pushing with --force-rewrites and this goes back in the timeline and makes it so that Baz retroactively had the right dependencies and now Fred, as of the previous Friday, no longer has this problem. (That way he still has the weekend). Now the failed build is cut off temporarily into a cycle in the package timeline that is disconnected from the rewrite. We stash it with ?hackage stash? until Monday at which time the dependency graph is 100 percent equalized and primed for new patches.? At this point we unstash Foo as of Friday and it is replaced by the Foo from the new timeline. Friday Fred needs to remain stashed lest he run into himself. The longer he can be avoided by his Monday self the better. Future work could include bots which automate pruning of artifacts from redundant branches. If this description was too abrupt, here is a diagram with a fuller description of the workflow: http://bit.ly/15IIGac I know there are some new ideas to take in here, and there is a little technical work necessary to make it feasible, but in my opinion if you can understand the current cabal situation, and you can understand how git and darcs work, then you should be able to understand this too. Hopefully by this time next year, we?ll be able to say that our problems with cabal have been truly wiped from our collective memory. HTH, HAND. Gershom From mail at joachim-breitner.de Wed Apr 1 11:14:47 2015 From: mail at joachim-breitner.de (Joachim Breitner) Date: Wed, 01 Apr 2015 13:14:47 +0200 Subject: Stable location for monomorphic foldr? Message-ID: <1427886887.21481.42.camel@joachim-breitner.de> Hi, I just stumbled over a FTP breakage: A RULES with "foldr" on the left hand side would no longer fire, because it would refer to Foldable.foldr, and not the monomorphic foldr. Adding #if MIN_VERSION_base(4,8,0) import Prelude hiding (foldr) import GHC.OldList (foldr) #endif to the file solved the problem for now, but GHC.OldList is supposed to go away eventually, so I believe we need a permanent location for the monomorphic foldr. Or will we simply not get rid of GHC.OldList at all? (One could argue that "foldr" on the left-hand-side of a RULE should work and that this is a GHC bug, though.) Greetings, Joachim -- Joachim ?nomeata? Breitner mail at joachim-breitner.de ? http://www.joachim-breitner.de/ Jabber: nomeata at joachim-breitner.de ? GPG-Key: 0xF0FBF51F Debian Developer: nomeata at debian.org -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: This is a digitally signed message part URL: From ttuegel at gmail.com Wed Apr 1 14:53:41 2015 From: ttuegel at gmail.com (Thomas Tuegel) Date: Wed, 1 Apr 2015 09:53:41 -0500 Subject: [Haskell-cafe] An Easy Solution to PVP Bounds and Cabal Hell In-Reply-To: References: Message-ID: Hi Gershom, On Tue, Mar 31, 2015 at 11:22 PM, Gershom B wrote: > One way to look at a particular build is in an n-dimensional state > space (of the Hilbert sort) determined by all its dependencies, not > least the compiler itself. The solver acts as a particle traversing > this space. But this description is too simple. Our state of > dependencies and constraints itself varies and grows over time. So > another approach is to think of the dependencies as a transitive > graph, where each node may vary along a time axis, and as they slide > along the axis, this in turn affects their children. We now have not > just one Hilbert space, but a collection of them related by > branching trees as authors locally modify the dependencies of their > packages. I don't know if you intended this to be a satirical remark about the package upper bounds, but I think you really hit the nail on the head. When we ask package authors to put upper bounds on their dependencies, what we are really doing is asking them to propagate information about _future_ incompatibilities back into the present. As none of us has access to future information [1], the upper bounds on our dependencies amount to a collection of bad guesses [2]. I think we should consider taking a more empirical approach [3]. One way (but certainly not the only way) to approach this would be to require packages to be uploaded to Hackage with a kind of "build-certificate," certifying that a successful build plan was possible given the state of Hackage at a particular timestamp. This allows us to infer minimal upper bounds for all of the package's transitive dependencies. Once the build-certificate is authenticated, Hackage only needs to store the latest timestamp of a successful build, so the overhead is very low. In this scheme, author-specified upper bounds would be relegated to ruling out known incompatibilities with already-released versions of dependencies. Of course, build failures will still occur. By using anonymous build-reporting to track the timestamp of the earliest failed build of a package, we can automatically infer the _true_ upper bounds on its dependencies. If contradictory reports occur, they can be resolved by the trustees or the package's maintainers. Just some food for thought. I hope the timing of my e-mail will not discourage anyone from taking my suggestions seriously. [1]. If I am mistaken and you think you do have access to future information, please respond privately; I have some questions for you about the stock market. [2]. If you've never had an upper bounds problem on a package you maintain, I'm happy for you, but there is mounting evidence that as a community, we are very bad guessers, on average. [3]. The PVP is orthogonal to this. It is a convenient set of assumptions and a reasonably good set of norms; nothing more. -- Thomas Tuegel From allbery.b at gmail.com Wed Apr 1 15:08:52 2015 From: allbery.b at gmail.com (Brandon Allbery) Date: Wed, 1 Apr 2015 11:08:52 -0400 Subject: [Haskell-cafe] An Easy Solution to PVP Bounds and Cabal Hell In-Reply-To: References: Message-ID: On Wed, Apr 1, 2015 at 10:53 AM, Thomas Tuegel wrote: > [2]. If you've never had an upper bounds problem on a package you > maintain, I'm happy for you, but there is mounting evidence that as a > community, we are very bad guessers, on average. > I think upper bound with easy way to "slip" it (--allow-newer, as already implemented) is the best we can do. There's already a lot of evidence that guessing wrong in the other direction can and does break large chunks of the ecosystem --- as much as certain developers would prefer to ignore the fact and/or arrange that everyone other than them has to deal with the breakage. -- brandon s allbery kf8nh sine nomine associates allbery.b at gmail.com ballbery at sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Wed Apr 1 19:59:02 2015 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 1 Apr 2015 15:59:02 -0400 Subject: Stable location for monomorphic foldr? In-Reply-To: <1427886887.21481.42.camel@joachim-breitner.de> References: <1427886887.21481.42.camel@joachim-breitner.de> Message-ID: The culprit seems to be that instance Foldable [] where elem = List.elem foldl = List.foldl foldl' = List.foldl' foldl1 = List.foldl1 foldr = List.foldr foldr1 = List.foldr1 length = List.length maximum = List.maximum minimum = List.minimum null = List.null product = List.product sum = List.sum toList = id delegates to monomorphic methods rather than implementing them directly. The early testing where we showed that it didn't break RULES was done with the final definitions in the class rather than delegating to GHC.OldList. Somewhere when reorganizing of the code we switched to this style and introduced this problem, making RULES much more brittle. =/ -Edward On Wed, Apr 1, 2015 at 7:14 AM, Joachim Breitner wrote: > Hi, > > I just stumbled over a FTP breakage: A RULES with "foldr" on the left > hand side would no longer fire, because it would refer to > Foldable.foldr, and not the monomorphic foldr. > > Adding > #if MIN_VERSION_base(4,8,0) > import Prelude hiding (foldr) > import GHC.OldList (foldr) > #endif > to the file solved the problem for now, but GHC.OldList is supposed to > go away eventually, so I believe we need a permanent location for the > monomorphic foldr. > > Or will we simply not get rid of GHC.OldList at all? > > (One could argue that "foldr" on the left-hand-side of a RULE should > work and that this is a GHC bug, though.) > > Greetings, > Joachim > > -- > Joachim ?nomeata? Breitner > mail at joachim-breitner.de ? http://www.joachim-breitner.de/ > Jabber: nomeata at joachim-breitner.de ? GPG-Key: 0xF0FBF51F > Debian Developer: nomeata at debian.org > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mail at joachim-breitner.de Thu Apr 2 07:59:02 2015 From: mail at joachim-breitner.de (Joachim Breitner) Date: Thu, 02 Apr 2015 09:59:02 +0200 Subject: Stable location for monomorphic foldr? In-Reply-To: <1427886887.21481.42.camel@joachim-breitner.de> References: <1427886887.21481.42.camel@joachim-breitner.de> Message-ID: <1427961542.1578.3.camel@joachim-breitner.de> Hi, Am Mittwoch, den 01.04.2015, 13:14 +0200 schrieb Joachim Breitner: > I just stumbled over a FTP breakage: A RULES with "foldr" on the left > hand side would no longer fire, because it would refer to > Foldable.foldr, and not the monomorphic foldr. > > Adding > #if MIN_VERSION_base(4,8,0) > import Prelude hiding (foldr) > import GHC.OldList (foldr) > #endif > to the file solved the problem for now, but GHC.OldList is supposed to > go away eventually, so I believe we need a permanent location for the > monomorphic foldr. in (accidentally?) private communication, Herbert suggested to use GHC.List, which also exports foldr. GHC.List does not show up in the haddock index, but does exist, and is likely to stay. Greetings, Joachim -- Joachim ?nomeata? Breitner mail at joachim-breitner.de ? http://www.joachim-breitner.de/ Jabber: nomeata at joachim-breitner.de ? GPG-Key: 0xF0FBF51F Debian Developer: nomeata at debian.org -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: This is a digitally signed message part URL: From dhelta.diaz at gmail.com Sat Apr 4 13:22:58 2015 From: dhelta.diaz at gmail.com (=?UTF-8?Q?Daniel_D=C3=ADaz_Casanueva?=) Date: Sat, 4 Apr 2015 09:22:58 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> Message-ID: I am (+1) on adding Semigroup as superclass of Monoid, being mappend/(<>) included in Semigroup. More than once I felt encouraged to include a neutral element in a type where I would have gladly go without having it. Importing semigroups from Hackage would mean to have two identical operators, idea I do not find attractive. About the path to choose for adoption, any of the ways described by Edward Kmett seems good to me (I can quickly update any of my packages to the change), but I'd rather avoid the longest one. Daniel D?az On Mar 30, 2015 9:09 PM, "Edward Kmett" wrote: > That definitely pushes me towards one of the "long" adoption paths. > > Here adding a Semigroup instance for Matrix actually works to get the same > symbol, but it has a different fixity (infixr 8). Same with (<>) in the > pretty printing libraries (infixl 6). > > In Data.Monoid and Data.Semigroup we have infixr 6 <> > > -Edward > > > On Mon, Mar 30, 2015 at 2:51 PM, Henning Thielemann < > lemming at henning-thielemann.de> wrote: > >> >> On Mon, 30 Mar 2015, Edward Kmett wrote: >> >> Collapse the first two steps into one step, but this means that nobody >>> gets any warning of new names coming >>> into the Prelude. On the other hand this would get us all the way to >>> done by 7.14. On one hand, the first >>> order consequence the amount of breakage caused by adding Semigroup to >>> Prelude and taking (<>) is almost >>> entirely confined to a handful of pretty printing libraries -- and we >>> already broke those same libraries by >>> taking (<$>). >>> >> >> Btw. hmatrix is another prominent package defining (<>) for matrix and >> related multiplications. >> > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dominic at steinitz.org Sat Apr 4 17:57:26 2015 From: dominic at steinitz.org (Dominic Steinitz) Date: Sat, 4 Apr 2015 18:57:26 +0100 Subject: A Random Strawman Message-ID: Hello All, Having skimmed the literature, run some tests and benchmarks: The current System.Random is broken: https://github.com/haskell/random/issues/25#issuecomment-87423142. Furthermore, this is recorded in at least two published papers: http://dl.acm.org/citation.cfm?id=2660195 and http://publications.lib.chalmers.se/records/fulltext/183348/local_183348.pdf. The tf-random package does not have this breakage and is based on good theoretical foundations. In my tests tf-random performs better than System.Random. As a result of which, I am very much inclined to suggest we replace the code in System.Random with tf-random. Before doing any more work on this, I?d like to understand what the next steps should be. How much review should be carried out? I have no reason to doubt the implementors have done a great job but should someone (who?) review the code more formally. If so what would the process / tools be? Tests in packages / applications may now fail as the (pseudo) random numbers will be different with this change. What should we do here? Alert folks (who and how?) that the may have to rebase their tests? Tell folks that 1.1 is deprecated and they should move to 2.0 (I think it?s right to indicate this is a completely new version)? Are there any other steps? FYI: I did look at Guy Steele et al. but I don?t believe there is currently a Haskell implementation of it, probably ruling it out as possible solution in the medium term. Dominic Steinitz dominic at steinitz.org http://idontgetoutmuch.wordpress.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Sat Apr 4 18:19:06 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Sat, 04 Apr 2015 18:19:06 +0000 Subject: A Random Strawman In-Reply-To: References: Message-ID: I actually think a bit more exploratory work and building up some testing and performance infrastructure in place are needed before doing any major version bump of randoms algorithm. Additonally theres a good chance we'll be having a gsoc student this summer who can help with this. Additionally, I will likely be able to put some work engineering time into exploring the algorithm choice. Point being, I want the next major version bump of random to raise the bar on engineering for prng libraries. So we have a bit of work to do first before we make a choice that forces upgrades on the universe. And we arent there yet On Sat, Apr 4, 2015, 2:00 PM Dominic Steinitz wrote: > Hello All, > > Having skimmed the literature, run some tests and benchmarks: > > > - The current System.Random is broken: > https://github.com/haskell/random/issues/25#issuecomment-87423142. > Furthermore, this is recorded in at least two published papers: > http://dl.acm.org/citation.cfm?id=2660195 and > http://publications.lib.chalmers.se/records/fulltext/183348/local_183348.pdf > . > - The tf-random package does not have this breakage and is based on > good theoretical foundations. > - In my tests tf-random performs better than System.Random. > > > As a result of which, I am very much inclined to suggest we replace the > code in System.Random with tf-random. Before doing any more work on this, > I?d like to understand what the next steps should be. > > > - How much review should be carried out? I have no reason to doubt the > implementors have done a great job but should someone (who?) review the > code more formally. If so what would the process / tools be? > - Tests in packages / applications may now fail as the (pseudo) random > numbers will be different with this change. What should we do here? Alert > folks (who and how?) that the may have to rebase their tests? Tell folks > that 1.1 is deprecated and they should move to 2.0 (I think it?s right to > indicate this is a completely new version)? > - Are there any other steps? > > > FYI: I did look at Guy Steele et al. but I don?t believe there is > currently a Haskell implementation of it, probably ruling it out as > possible solution in the medium term. > > Dominic Steinitz > dominic at steinitz.org > http://idontgetoutmuch.wordpress.com > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From blamario at ciktel.net Sun Apr 5 15:05:20 2015 From: blamario at ciktel.net (=?UTF-8?B?TWFyaW8gQmxhxb5ldmnEhw==?=) Date: Sun, 05 Apr 2015 11:05:20 -0400 Subject: Proposal: Add a Semigroup-equivalent superclass of Alternative In-Reply-To: <1427631633145-5767835.post@n5.nabble.com> References: <1427631633145-5767835.post@n5.nabble.com> Message-ID: <55214F30.2000706@ciktel.net> On 03/29/2015 08:20 AM, Jeremy wrote: > The proposal to make Semigroup a superclass of Monoid was discussed a while > ago [1], and the conclusion was to "put this off until the dust has settled > from the AMP and FT changes". It has occurred to me that the Alternative class, which is pretty much a constructor version of Monoid, would benefit from the same treatment. The greatest difficulty seems to be in finding the name for the Semigroup-equivalent superclass of Alternative. For lack of imagination,I'll just call it Semigroup1: class Applicative f => Semigroup1 f where (<|>) :: f a -> f a -> f a some :: f a -> f [a] many :: f a -> f [a] class Semigroup1 f => Alternative f where empty :: f a The rationale for this change: 1. All the theoretical arguments for introducing Semigroup carry over with no change. 2. There are existing data types that could be made instances of Semigroup1, and not of Alternative. I have not performed any comprehensive survey, but QuickCheck's Gen type can provide one example: instance Semigroup1 Gen where f <|> g = oneof [f, g] 3. Most interesting instances of Alternative are various parser types. A parser type that doesn't define empty is a parser that cannot fail by construction. That makes intuitive sense. I can imagine some benefits from a set of parser combinators that generated two types, only one of which could fail. Fill in the blanks: instance Semigroup1 IrrefutableParser instance Alternative Parser token :: a -> Parser a optional :: Parser a -> IrrefutableParser (Maybe a) many0 :: Parser a -> IrrefutableParser [a] There are, of course, two important differences between the Monoid and Alternative situation. First, the Semigroup class already exists, if not in base. That only means the proposal outlined above requires more critique and bikeshedding. The other difference is that the Semigroup operator (<>) is different from the Monoid operator mappend. This is mostly an unfortunate backward compatibility issue, but it does have a benefit of allowing the two classes to exist independently for a while before they are brought together. If we really, *really* desire the same doubtful benefit for Alternative, we can use a new operator name for the Semigroup1 class (I refuse to provide one in this proposal) and then eventually stipulate (<|>) = i-refuse-to-provide-one-in-this-proposal. My preference, if available, would be to just move the <|> operator into the superclass in 7.12. It's such a perfect operator name. Without a new GHC extension, however, this would mean that every existing instance of Alternative would be broken in 7.12. Furthermore, there would be no way to write an Alternative instance valid in both 7.10 and 7.12 without CPP directives. The only saving grace here is that the Alternative instances are relatively few, and it may just be possible to coordinate all the changes. So, here's a question to all authors of parser libraries and everybody else that has defined Alternative instances: would you be able and willing to add CPP directives to your code for this purpose? For everybody else: this is a proposal, so vote on it. From roma at ro-che.info Sun Apr 5 15:56:20 2015 From: roma at ro-che.info (Roman Cheplyaka) Date: Sun, 05 Apr 2015 18:56:20 +0300 Subject: Proposal: Add a Semigroup-equivalent superclass of Alternative In-Reply-To: <55214F30.2000706@ciktel.net> References: <1427631633145-5767835.post@n5.nabble.com> <55214F30.2000706@ciktel.net> Message-ID: <55215B24.7040806@ro-che.info> FWIW, Ed Kmett has this already in his semigroupoids package as Data.Functor.Alt: https://hackage.haskell.org/package/semigroupoids On 05/04/15 18:05, Mario Bla?evi? wrote: > On 03/29/2015 08:20 AM, Jeremy wrote: >> The proposal to make Semigroup a superclass of Monoid was discussed a >> while >> ago [1], and the conclusion was to "put this off until the dust has >> settled >> from the AMP and FT changes". > > It has occurred to me that the Alternative class, which is pretty > much a constructor version of Monoid, would benefit from the same > treatment. The greatest difficulty seems to be in finding the name for > the Semigroup-equivalent superclass of Alternative. For lack of > imagination,I'll just call it Semigroup1: > > class Applicative f => Semigroup1 f where > (<|>) :: f a -> f a -> f a > some :: f a -> f [a] > many :: f a -> f [a] > > class Semigroup1 f => Alternative f where > empty :: f a > > The rationale for this change: > > 1. All the theoretical arguments for introducing Semigroup carry over > with no change. > > 2. There are existing data types that could be made instances of > Semigroup1, and not of Alternative. I have not performed any > comprehensive survey, but QuickCheck's Gen type can provide one example: > > instance Semigroup1 Gen where > f <|> g = oneof [f, g] > > 3. Most interesting instances of Alternative are various parser types. A > parser type that doesn't define empty is a parser that cannot fail by > construction. That makes intuitive sense. I can imagine some benefits > from a set of parser combinators that generated two types, only one of > which could fail. Fill in the blanks: > > instance Semigroup1 IrrefutableParser > instance Alternative Parser > > token :: a -> Parser a > optional :: Parser a -> IrrefutableParser (Maybe a) > many0 :: Parser a -> IrrefutableParser [a] > > There are, of course, two important differences between the Monoid > and Alternative situation. First, the Semigroup class already exists, if > not in base. That only means the proposal outlined above requires more > critique and bikeshedding. > > The other difference is that the Semigroup operator (<>) is > different from the Monoid operator mappend. This is mostly an > unfortunate backward compatibility issue, but it does have a benefit of > allowing the two classes to exist independently for a while before they > are brought together. If we really, *really* desire the same doubtful > benefit for Alternative, we can use a new operator name for the > Semigroup1 class (I refuse to provide one in this proposal) and then > eventually stipulate (<|>) = i-refuse-to-provide-one-in-this-proposal. > > My preference, if available, would be to just move the <|> operator > into the superclass in 7.12. It's such a perfect operator name. Without > a new GHC extension, however, this would mean that every existing > instance of Alternative would be broken in 7.12. Furthermore, there > would be no way to write an Alternative instance valid in both 7.10 and > 7.12 without CPP directives. The only saving grace here is that the > Alternative instances are relatively few, and it may just be possible to > coordinate all the changes. > > So, here's a question to all authors of parser libraries and > everybody else that has defined Alternative instances: would you be able > and willing to add CPP directives to your code for this purpose? > > For everybody else: this is a proposal, so vote on it. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > From blamario at ciktel.net Sun Apr 5 16:06:02 2015 From: blamario at ciktel.net (=?UTF-8?B?TWFyaW8gQmxhxb5ldmnEhw==?=) Date: Sun, 05 Apr 2015 12:06:02 -0400 Subject: Proposal: Add a Semigroup-equivalent superclass of Alternative In-Reply-To: <55215B24.7040806@ro-che.info> References: <1427631633145-5767835.post@n5.nabble.com> <55214F30.2000706@ciktel.net> <55215B24.7040806@ro-che.info> Message-ID: <55215D6A.40901@ciktel.net> On 04/05/2015 11:56 AM, Roman Cheplyaka wrote: > FWIW, Ed Kmett has this already in his semigroupoids package as > Data.Functor.Alt: > https://hackage.haskell.org/package/semigroupoids Of course he does, I don't know why I didn't look there. Well I like the Alt class name but I'd still prefer to reuse <|> if possible. If I had to guess, I'd assume the operator was a strict variant of <$> or <*>. > > On 05/04/15 18:05, Mario Bla?evi? wrote: >> On 03/29/2015 08:20 AM, Jeremy wrote: >>> The proposal to make Semigroup a superclass of Monoid was discussed a >>> while >>> ago [1], and the conclusion was to "put this off until the dust has >>> settled >>> from the AMP and FT changes". >> It has occurred to me that the Alternative class, which is pretty >> much a constructor version of Monoid, would benefit from the same >> treatment. The greatest difficulty seems to be in finding the name for >> the Semigroup-equivalent superclass of Alternative. For lack of >> imagination,I'll just call it Semigroup1: >> >> class Applicative f => Semigroup1 f where >> (<|>) :: f a -> f a -> f a >> some :: f a -> f [a] >> many :: f a -> f [a] >> >> class Semigroup1 f => Alternative f where >> empty :: f a >> >> The rationale for this change: >> >> 1. All the theoretical arguments for introducing Semigroup carry over >> with no change. >> >> 2. There are existing data types that could be made instances of >> Semigroup1, and not of Alternative. I have not performed any >> comprehensive survey, but QuickCheck's Gen type can provide one example: >> >> instance Semigroup1 Gen where >> f <|> g = oneof [f, g] >> >> 3. Most interesting instances of Alternative are various parser types. A >> parser type that doesn't define empty is a parser that cannot fail by >> construction. That makes intuitive sense. I can imagine some benefits >> from a set of parser combinators that generated two types, only one of >> which could fail. Fill in the blanks: >> >> instance Semigroup1 IrrefutableParser >> instance Alternative Parser >> >> token :: a -> Parser a >> optional :: Parser a -> IrrefutableParser (Maybe a) >> many0 :: Parser a -> IrrefutableParser [a] >> >> There are, of course, two important differences between the Monoid >> and Alternative situation. First, the Semigroup class already exists, if >> not in base. That only means the proposal outlined above requires more >> critique and bikeshedding. >> >> The other difference is that the Semigroup operator (<>) is >> different from the Monoid operator mappend. This is mostly an >> unfortunate backward compatibility issue, but it does have a benefit of >> allowing the two classes to exist independently for a while before they >> are brought together. If we really, *really* desire the same doubtful >> benefit for Alternative, we can use a new operator name for the >> Semigroup1 class (I refuse to provide one in this proposal) and then >> eventually stipulate (<|>) = i-refuse-to-provide-one-in-this-proposal. >> >> My preference, if available, would be to just move the <|> operator >> into the superclass in 7.12. It's such a perfect operator name. Without >> a new GHC extension, however, this would mean that every existing >> instance of Alternative would be broken in 7.12. Furthermore, there >> would be no way to write an Alternative instance valid in both 7.10 and >> 7.12 without CPP directives. The only saving grace here is that the >> Alternative instances are relatively few, and it may just be possible to >> coordinate all the changes. >> >> So, here's a question to all authors of parser libraries and >> everybody else that has defined Alternative instances: would you be able >> and willing to add CPP directives to your code for this purpose? >> >> For everybody else: this is a proposal, so vote on it. >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > From ekmett at gmail.com Sun Apr 5 16:13:18 2015 From: ekmett at gmail.com (Edward Kmett) Date: Sun, 5 Apr 2015 12:13:18 -0400 Subject: Proposal: Add a Semigroup-equivalent superclass of Alternative In-Reply-To: <55214F30.2000706@ciktel.net> References: <1427631633145-5767835.post@n5.nabble.com> <55214F30.2000706@ciktel.net> Message-ID: There are many points in the design space. * There is a pure Semigroup1, which acts as an indexed semigroup, without the Applicative superclass, which is the Alt class in the semigroupoids package. * There is a Alternative minus empty, which you've proposed here. But then even within each of those options we have several choices. The laws for how Applicative and Alternative relate are subject to all the same problems as the laws between Monad and MonadPlus and the situation doesn't get any better here. catch vs. right distribution rears its head all over again. The empty laws, which get much more complicated on the Alternative front at least don't show up. Finally, there is another discussion this proposal may actively interfere with that has frankly, a lot more traction: What to do with 'fail' in Monad. Lennart has been a rather vocal proponent about finally doing something about that situation. To produce a viable MonadFail story one very solid path would be to lift the question up to the Applicative level, at which point in time, moving fail to an mfail in side of a class that depends on Applicative may be a good home, but that is more or less switching to a unit-then-add-an-associative operation style, rather than this. With Applicative as a superclass of Monad we were asking folks to adopt an abstraction they had already accepted and used for several years. With Semigroup as a superclass of Monoid, the abstraction has already seen many years of productive use. Haskell is remarkably bad at dealing with very fine-grained class hierarchies. With all of that in mind, I'm personally -1 on this addition. I don't think it rises to the level of traction needed to ask everyone everywhere to change all the code that they have ever written that involves MonadPlus, when the design space remains as large as it is. -Edward On Sun, Apr 5, 2015 at 11:05 AM, Mario Bla?evi? wrote: > On 03/29/2015 08:20 AM, Jeremy wrote: > >> The proposal to make Semigroup a superclass of Monoid was discussed a >> while >> ago [1], and the conclusion was to "put this off until the dust has >> settled >> from the AMP and FT changes". >> > > It has occurred to me that the Alternative class, which is pretty much > a constructor version of Monoid, would benefit from the same treatment. The > greatest difficulty seems to be in finding the name for the > Semigroup-equivalent superclass of Alternative. For lack of > imagination,I'll just call it Semigroup1: > > class Applicative f => Semigroup1 f where > (<|>) :: f a -> f a -> f a > some :: f a -> f [a] > many :: f a -> f [a] > > class Semigroup1 f => Alternative f where > empty :: f a > > The rationale for this change: > > 1. All the theoretical arguments for introducing Semigroup carry over with > no change. > > 2. There are existing data types that could be made instances of > Semigroup1, and not of Alternative. I have not performed any comprehensive > survey, but QuickCheck's Gen type can provide one example: > > instance Semigroup1 Gen where > f <|> g = oneof [f, g] > > 3. Most interesting instances of Alternative are various parser types. A > parser type that doesn't define empty is a parser that cannot fail by > construction. That makes intuitive sense. I can imagine some benefits from > a set of parser combinators that generated two types, only one of which > could fail. Fill in the blanks: > > instance Semigroup1 IrrefutableParser > instance Alternative Parser > > token :: a -> Parser a > optional :: Parser a -> IrrefutableParser (Maybe a) > many0 :: Parser a -> IrrefutableParser [a] > > There are, of course, two important differences between the Monoid and > Alternative situation. First, the Semigroup class already exists, if not in > base. That only means the proposal outlined above requires more critique > and bikeshedding. > > The other difference is that the Semigroup operator (<>) is different > from the Monoid operator mappend. This is mostly an unfortunate backward > compatibility issue, but it does have a benefit of allowing the two classes > to exist independently for a while before they are brought together. If we > really, *really* desire the same doubtful benefit for Alternative, we can > use a new operator name for the Semigroup1 class (I refuse to provide one > in this proposal) and then eventually stipulate (<|>) = > i-refuse-to-provide-one-in-this-proposal. > > My preference, if available, would be to just move the <|> operator > into the superclass in 7.12. It's such a perfect operator name. Without a > new GHC extension, however, this would mean that every existing instance of > Alternative would be broken in 7.12. Furthermore, there would be no way to > write an Alternative instance valid in both 7.10 and 7.12 without CPP > directives. The only saving grace here is that the Alternative instances > are relatively few, and it may just be possible to coordinate all the > changes. > > So, here's a question to all authors of parser libraries and everybody > else that has defined Alternative instances: would you be able and willing > to add CPP directives to your code for this purpose? > > For everybody else: this is a proposal, so vote on it. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sun Apr 5 16:15:13 2015 From: ekmett at gmail.com (Edward Kmett) Date: Sun, 5 Apr 2015 12:15:13 -0400 Subject: Proposal: Add a Semigroup-equivalent superclass of Alternative In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <55214F30.2000706@ciktel.net> Message-ID: Rather, the Alt in semigroups is an indexed version with a Functor constraint: a sort of middle ground. There is also a possibly quite useful indexed version without a Functor constraint that can be polykinded. That one is useful for working with things like Conor McBride's Kleisli Arrows of Outrageous Fortune, when it comes time to talk about indexed writer monads and indexed update monads. -Edward On Sun, Apr 5, 2015 at 12:13 PM, Edward Kmett wrote: > There are many points in the design space. > > * There is a pure Semigroup1, which acts as an indexed semigroup, without > the Applicative superclass, which is the Alt class in the semigroupoids > package. > > * There is a Alternative minus empty, which you've proposed here. > > But then even within each of those options we have several choices. > > The laws for how Applicative and Alternative relate are subject to all the > same problems as the laws between Monad and MonadPlus and the situation > doesn't get any better here. catch vs. right distribution rears its head > all over again. > > The empty laws, which get much more complicated on the Alternative front > at least don't show up. > > Finally, there is another discussion this proposal may actively interfere > with that has frankly, a lot more traction: What to do with 'fail' in > Monad. Lennart has been a rather vocal proponent about finally doing > something about that situation. To produce a viable MonadFail story one > very solid path would be to lift the question up to the Applicative level, > at which point in time, moving fail to an mfail in side of a class that > depends on Applicative may be a good home, but that is more or less > switching to a unit-then-add-an-associative operation style, rather than > this. > > With Applicative as a superclass of Monad we were asking folks to adopt an > abstraction they had already accepted and used for several years. > > With Semigroup as a superclass of Monoid, the abstraction has already seen > many years of productive use. > > Haskell is remarkably bad at dealing with very fine-grained class > hierarchies. > > With all of that in mind, I'm personally -1 on this addition. I don't > think it rises to the level of traction needed to ask everyone everywhere > to change all the code that they have ever written that involves MonadPlus, > when the design space remains as large as it is. > > -Edward > > On Sun, Apr 5, 2015 at 11:05 AM, Mario Bla?evi? > wrote: > >> On 03/29/2015 08:20 AM, Jeremy wrote: >> >>> The proposal to make Semigroup a superclass of Monoid was discussed a >>> while >>> ago [1], and the conclusion was to "put this off until the dust has >>> settled >>> from the AMP and FT changes". >>> >> >> It has occurred to me that the Alternative class, which is pretty >> much a constructor version of Monoid, would benefit from the same >> treatment. The greatest difficulty seems to be in finding the name for the >> Semigroup-equivalent superclass of Alternative. For lack of >> imagination,I'll just call it Semigroup1: >> >> class Applicative f => Semigroup1 f where >> (<|>) :: f a -> f a -> f a >> some :: f a -> f [a] >> many :: f a -> f [a] >> >> class Semigroup1 f => Alternative f where >> empty :: f a >> >> The rationale for this change: >> >> 1. All the theoretical arguments for introducing Semigroup carry over >> with no change. >> >> 2. There are existing data types that could be made instances of >> Semigroup1, and not of Alternative. I have not performed any comprehensive >> survey, but QuickCheck's Gen type can provide one example: >> >> instance Semigroup1 Gen where >> f <|> g = oneof [f, g] >> >> 3. Most interesting instances of Alternative are various parser types. A >> parser type that doesn't define empty is a parser that cannot fail by >> construction. That makes intuitive sense. I can imagine some benefits from >> a set of parser combinators that generated two types, only one of which >> could fail. Fill in the blanks: >> >> instance Semigroup1 IrrefutableParser >> instance Alternative Parser >> >> token :: a -> Parser a >> optional :: Parser a -> IrrefutableParser (Maybe a) >> many0 :: Parser a -> IrrefutableParser [a] >> >> There are, of course, two important differences between the Monoid >> and Alternative situation. First, the Semigroup class already exists, if >> not in base. That only means the proposal outlined above requires more >> critique and bikeshedding. >> >> The other difference is that the Semigroup operator (<>) is different >> from the Monoid operator mappend. This is mostly an unfortunate backward >> compatibility issue, but it does have a benefit of allowing the two classes >> to exist independently for a while before they are brought together. If we >> really, *really* desire the same doubtful benefit for Alternative, we can >> use a new operator name for the Semigroup1 class (I refuse to provide one >> in this proposal) and then eventually stipulate (<|>) = >> i-refuse-to-provide-one-in-this-proposal. >> >> My preference, if available, would be to just move the <|> operator >> into the superclass in 7.12. It's such a perfect operator name. Without a >> new GHC extension, however, this would mean that every existing instance of >> Alternative would be broken in 7.12. Furthermore, there would be no way to >> write an Alternative instance valid in both 7.10 and 7.12 without CPP >> directives. The only saving grace here is that the Alternative instances >> are relatively few, and it may just be possible to coordinate all the >> changes. >> >> So, here's a question to all authors of parser libraries and >> everybody else that has defined Alternative instances: would you be able >> and willing to add CPP directives to your code for this purpose? >> >> For everybody else: this is a proposal, so vote on it. >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From menonvikas at gmail.com Sun Apr 5 16:46:39 2015 From: menonvikas at gmail.com (Vikas Menon) Date: Sun, 5 Apr 2015 12:46:39 -0400 Subject: Proposal for a generic showIntAtBase Message-ID: Hi, The current implementation of showIntAtBase in Numeric is limited to Chars currently. *showIntAtBase* * :: (Integral a, Show a) => a -> (Int -> Char) -> a -> ShowS* The 2 reasons for this constraint is: a) We only accept functions of the form (Int -> Char) b) An implicit concatenation using (:) I'd like to propose a new function showIntAtBaseGeneric that removes the (Int -> Char) function constraint and takes an additional function to replace the implicit (:) operator. *showIntAtBaseGeneric* * :: (Integral a1, Num b, Show a1) =>* * a1 -> (b -> a) -> (a -> s -> s) -> a1 -> s -> s* Now showIntAtBase may be implemented as: *showIntAtBase :: (Integral a, Show a) => a -> (Int -> Char) -> a -> ShowS* *showIntAtBase base toChr n0 r0 = showIntAtBaseGeneric base toChr (:) n0 r0* The API and behavior of showIntAtBase remains unchanged while allowing for generic conversions not limited to Chars alone. *Example: * *?> showIntAtBaseGeneric 26 id (:) 500 [] -- convert 500 to base26 and provide output as a list.* *[19,6]* Please let me know thoughts/concerns if any to this proposal. Cheers, Vikas -------------- next part -------------- An HTML attachment was scrubbed... URL: From blamario at ciktel.net Sun Apr 5 17:05:31 2015 From: blamario at ciktel.net (=?UTF-8?B?TWFyaW8gQmxhxb5ldmnEhw==?=) Date: Sun, 05 Apr 2015 13:05:31 -0400 Subject: Proposal: Add a Semigroup-equivalent superclass of Alternative In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <55214F30.2000706@ciktel.net> Message-ID: <55216B5B.1090909@ciktel.net> On 04/05/2015 12:13 PM, Edward Kmett wrote: > There are many points in the design space. > > * There is a pure Semigroup1, which acts as an indexed semigroup, > without the Applicative superclass, which is the Alt class in the > semigroupoids package. Yes, I suppose that makes Semigroup1 a wrong name for this proposal, but do these points in the design space actually conflict with > * There is a Alternative minus empty, which you've proposed here. I mean, Alternative is already in wide use in parsers. From this starting point, AlternativeMinusEmpty would clearly be a useful thing on its own: it's an abstraction of irrefutable parsers and generators. If we later find a use for the plain Semigroup1 or Functor => Alt, backward-compatibility aside, they could just become superclasses of AlternativeMinusEmpty. Which would then lead to the problem where > ... > Haskell is remarkably bad at dealing with very fine-grained class > hierarchies. You've blogged about this in https://www.fpcomplete.com/user/edwardk/editorial/procrustean-mathematics and I understand your concerns, even if I'm personally rooting for the centipedes. I have to say that, both when I read the article, and re-reading it again now, I wished for a clearer statement of the problem. Is it so fundamental in mathematics, as you seem to imply, that no programming language will ever be able to reconcile alternative abstractions? Or is it only a problem with Haskell and the proposed superclass extensions, as you suggest in > Even with one of the superclass default proposals, you get no real > code reuse for any form of transformer, and the existing default > signature mechanism runs "the wrong way" in such a way that it even > forces you to put everything in the same module. In the latter case, can you point to a design, or a sketch of it, that would be better? > > With all of that in mind, I'm personally -1 on this addition. I don't > think it rises to the level of traction needed to ask everyone > everywhere to change all the code that they have ever written that > involves MonadPlus, when the design space remains as large as it is. This proposal wouldn't touch MonadPlus with a ten-foot pole. From lemming at henning-thielemann.de Mon Apr 6 10:35:29 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Mon, 6 Apr 2015 12:35:29 +0200 (CEST) Subject: Proposal for a generic showIntAtBase In-Reply-To: References: Message-ID: On Sun, 5 Apr 2015, Vikas Menon wrote: > Example:? > ?> ?showIntAtBaseGeneric 26 id (:) 500 [] -- convert 500 to base26 and provide output as a list. > [19,6] > > Please let me know thoughts/concerns if any to this proposal. That is, you want to decompose a number into digits of an arbitrary base? I would not associate that with "show". I have implemented this in some flavors: https://hackage.haskell.org/package/numeric-prelude-0.4.2/docs/Algebra-IntegralDomain.html#v:decomposeVarPositional decomposePositional in http://code.haskell.org/~thielema/htam/src/NumberTheory.hs From tikhon at jelv.is Mon Apr 6 17:21:55 2015 From: tikhon at jelv.is (Tikhon Jelvis) Date: Mon, 6 Apr 2015 10:21:55 -0700 Subject: Proposal for a generic showIntAtBase In-Reply-To: References: Message-ID: Decomposing numbers into arbitrary bases *already* exists as showIntAtBase. Vikas's proposal is about generalizing this existing function to output more than just strings and characters. Whether the existing naming scheme makes sense is a separate issue. (The whole Numeric module is weird, from the non-hierarchical name through function like showFFloatAlt.) On Mon, Apr 6, 2015 at 3:35 AM, Henning Thielemann < lemming at henning-thielemann.de> wrote: > > On Sun, 5 Apr 2015, Vikas Menon wrote: > > Example: >> ?> showIntAtBaseGeneric 26 id (:) 500 [] -- convert 500 to base26 and >> provide output as a list. >> [19,6] >> >> Please let me know thoughts/concerns if any to this proposal. >> > > That is, you want to decompose a number into digits of an arbitrary base? > I would not associate that with "show". I have implemented this in some > flavors: > https://hackage.haskell.org/package/numeric-prelude-0.4.2/ > docs/Algebra-IntegralDomain.html#v:decomposeVarPositional > decomposePositional in > http://code.haskell.org/~thielema/htam/src/NumberTheory.hs > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Mon Apr 6 17:52:25 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Mon, 6 Apr 2015 19:52:25 +0200 (CEST) Subject: Proposal for a generic showIntAtBase In-Reply-To: References: Message-ID: On Mon, 6 Apr 2015, Tikhon Jelvis wrote: > Decomposing numbers into arbitrary bases *already* exists as showIntAtBase. Vikas's proposal is about > generalizing this existing function to output more than just strings and characters. With "digits" I meant something different from "Char", e.g. Int. If this is the goal of the proposal then Vikas could use the implementations I pointed to, for now. I do not see a need to have the function in "base". From evincarofautumn at gmail.com Mon Apr 6 18:51:32 2015 From: evincarofautumn at gmail.com (Jon Purdy) Date: Mon, 6 Apr 2015 11:51:32 -0700 Subject: Proposal for a generic showIntAtBase In-Reply-To: References: Message-ID: Could you offer a specific use case? When I need to convert a number to its representation in some base, it?s because I?m displaying or serialising it. A base is a notation (or a variant of a notation) and it seems sensible to represent such notations with characters. This raises another question: why is the base parameter overloaded? base?s implementation of showIntAtBase uses quotRem on the base and the number, but it could easily cast the base from Int. I imagine the answer is ?historical accident?. On Sun, Apr 5, 2015 at 9:46 AM, Vikas Menon wrote: > > Hi, > > The current implementation of showIntAtBase in Numeric is limited to Chars currently. > > showIntAtBase > :: (Integral a, Show a) => a -> (Int -> Char) -> a -> ShowS > > The 2 reasons for this constraint is: > a) We only accept functions of the form (Int -> Char) > b) An implicit concatenation using (:) > > I'd like to propose a new function showIntAtBaseGeneric that removes the (Int -> Char) function constraint and takes an additional function to replace the implicit (:) operator. > > showIntAtBaseGeneric > :: (Integral a1, Num b, Show a1) => > a1 -> (b -> a) -> (a -> s -> s) -> a1 -> s -> s > > Now showIntAtBase may be implemented as: > > showIntAtBase :: (Integral a, Show a) => a -> (Int -> Char) -> a -> ShowS > showIntAtBase base toChr n0 r0 = showIntAtBaseGeneric base toChr (:) n0 r0 > > The API and behavior of showIntAtBase remains unchanged while allowing for generic conversions not limited to Chars alone. > > Example: > ?> showIntAtBaseGeneric 26 id (:) 500 [] -- convert 500 to base26 and provide output as a list. > [19,6] > > Please let me know thoughts/concerns if any to this proposal. > > Cheers, > Vikas > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > From lemming at henning-thielemann.de Mon Apr 6 19:04:33 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Mon, 6 Apr 2015 21:04:33 +0200 (CEST) Subject: Proposal for a generic showIntAtBase In-Reply-To: References: Message-ID: On Mon, 6 Apr 2015, Jon Purdy wrote: > Could you offer a specific use case? When I need to convert a number > to its representation in some base, it?s because I?m displaying or > serialising it. A base is a notation (or a variant of a notation) and > it seems sensible to represent such notations with characters. E.g. you can use it to pack a tuple of small integers space efficiently into a larger integer type. E.g. you can pack 3 integers from the range 0..4 into 7 bits using a base-5 representation, but you would need 9 bits if you reserve three bits for every small integer. Using the positional representation you can also convert between tupled and linear indexes of an array with equal extents in all dimensions (i.e. a hypercube). Both examples also work with mixed-base representations. From ekmett at gmail.com Mon Apr 6 20:50:20 2015 From: ekmett at gmail.com (Edward Kmett) Date: Mon, 6 Apr 2015 16:50:20 -0400 Subject: A Random Strawman In-Reply-To: References: Message-ID: If we're going to switch out algorithms completely then a first digit major version bump seems entirely warranted. Pulling in tf-random's code entirely is definitely one way to move forward, and it has the benefit of being a relatively simple migration. As for tf-random vs. trying out a port of Guy Steele's work to Haskell. That is more a question of time and available engineering effort. Do we take the short term win or look to see how much further performance we could eke out by going down Guy's path? Given that tf-random is already there and working, I'd be inclined to take the longer path forward. -Edward On Sat, Apr 4, 2015 at 1:57 PM, Dominic Steinitz wrote: > Hello All, > > Having skimmed the literature, run some tests and benchmarks: > > > - The current System.Random is broken: > https://github.com/haskell/random/issues/25#issuecomment-87423142. > Furthermore, this is recorded in at least two published papers: > http://dl.acm.org/citation.cfm?id=2660195 and > http://publications.lib.chalmers.se/records/fulltext/183348/local_183348.pdf > . > - The tf-random package does not have this breakage and is based on > good theoretical foundations. > - In my tests tf-random performs better than System.Random. > > > As a result of which, I am very much inclined to suggest we replace the > code in System.Random with tf-random. Before doing any more work on this, > I?d like to understand what the next steps should be. > > > - How much review should be carried out? I have no reason to doubt the > implementors have done a great job but should someone (who?) review the > code more formally. If so what would the process / tools be? > - Tests in packages / applications may now fail as the (pseudo) random > numbers will be different with this change. What should we do here? Alert > folks (who and how?) that the may have to rebase their tests? Tell folks > that 1.1 is deprecated and they should move to 2.0 (I think it?s right to > indicate this is a completely new version)? > - Are there any other steps? > > > FYI: I did look at Guy Steele et al. but I don?t believe there is > currently a Haskell implementation of it, probably ruling it out as > possible solution in the medium term. > > Dominic Steinitz > dominic at steinitz.org > http://idontgetoutmuch.wordpress.com > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Mon Apr 6 21:39:24 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Mon, 06 Apr 2015 21:39:24 +0000 Subject: A Random Strawman In-Reply-To: References: Message-ID: Well said, a lot of the tools that depend on a good quality RNG have migrated to tf random and friends. So a thoughtful time scale is very much the way to go On Mon, Apr 6, 2015, 4:50 PM Edward Kmett wrote: > If we're going to switch out algorithms completely then a first digit > major version bump seems entirely warranted. > > Pulling in tf-random's code entirely is definitely one way to move > forward, and it has the benefit of being a relatively simple migration. > > As for tf-random vs. trying out a port of Guy Steele's work to Haskell. > > That is more a question of time and available engineering effort. > > Do we take the short term win or look to see how much further performance > we could eke out by going down Guy's path? > > Given that tf-random is already there and working, I'd be inclined to take > the longer path forward. > > -Edward > > > On Sat, Apr 4, 2015 at 1:57 PM, Dominic Steinitz > wrote: > >> Hello All, >> >> Having skimmed the literature, run some tests and benchmarks: >> >> >> - The current System.Random is broken: https://github.com/haskell/ >> random/issues/25#issuecomment-87423142 >> . >> Furthermore, this is recorded in at least two published papers: >> http://dl.acm.org/citation.cfm?id=2660195 >> and >> http://publications.lib.chalmers.se/records/fulltext/ >> 183348/local_183348.pdf >> >> . >> - The tf-random package does not have this breakage and is based on >> good theoretical foundations. >> - In my tests tf-random performs better than System.Random. >> >> >> As a result of which, I am very much inclined to suggest we replace the >> code in System.Random with tf-random. Before doing any more work on this, >> I?d like to understand what the next steps should be. >> >> >> - How much review should be carried out? I have no reason to doubt >> the implementors have done a great job but should someone (who?) review the >> code more formally. If so what would the process / tools be? >> - Tests in packages / applications may now fail as the (pseudo) >> random numbers will be different with this change. What should we do here? >> Alert folks (who and how?) that the may have to rebase their tests? Tell >> folks that 1.1 is deprecated and they should move to 2.0 (I think it?s >> right to indicate this is a completely new version)? >> - Are there any other steps? >> >> >> FYI: I did look at Guy Steele et al. but I don?t believe there is >> currently a Haskell implementation of it, probably ruling it out as >> possible solution in the medium term. >> >> Dominic Steinitz >> dominic at steinitz.org >> http://idontgetoutmuch.wordpress.com >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From menonvikas at gmail.com Mon Apr 6 21:43:19 2015 From: menonvikas at gmail.com (Vikas Menon) Date: Mon, 6 Apr 2015 17:43:19 -0400 Subject: Proposal for a generic showIntAtBase In-Reply-To: References: Message-ID: The idea is the same function can deal with Chars, "digits" or any other types (UTF16 for instance). This would subsume the current implementation of decomposeVarPositional and deal with many more. On Mon, Apr 6, 2015 at 3:04 PM, Henning Thielemann < lemming at henning-thielemann.de> wrote: > > On Mon, 6 Apr 2015, Jon Purdy wrote: > > Could you offer a specific use case? When I need to convert a number >> to its representation in some base, it?s because I?m displaying or >> serialising it. A base is a notation (or a variant of a notation) and >> it seems sensible to represent such notations with characters. >> > > E.g. you can use it to pack a tuple of small integers space efficiently > into a larger integer type. E.g. you can pack 3 integers from the range > 0..4 into 7 bits using a base-5 representation, but you would need 9 bits > if you reserve three bits for every small integer. > > Using the positional representation you can also convert between tupled > and linear indexes of an array with equal extents in all dimensions (i.e. a > hypercube). > > Both examples also work with mixed-base representations. -------------- next part -------------- An HTML attachment was scrubbed... URL: From winterkoninkje at gmail.com Tue Apr 7 02:46:18 2015 From: winterkoninkje at gmail.com (wren romano) Date: Mon, 6 Apr 2015 22:46:18 -0400 Subject: ANN: logfloat 0.13.3 In-Reply-To: References: Message-ID: On Mon, Mar 30, 2015 at 4:38 AM, Henning Thielemann wrote: > On Sun, 29 Mar 2015, wren romano wrote: > >> -------------------------------------------- >> -- logfloat 0.13.3 >> -------------------------------------------- >> >> This package provides a type for storing numbers in the log-domain, >> primarily useful for preventing underflow when multiplying many >> probabilities as in HMMs and other probabilistic models. The package >> also provides modules for dealing with floating numbers correctly. > > I am currently working on > http://hub.darcs.net/thielema/hmm-hmatrix > > It does not need log-numbers because it normalizes all temporary results. > This way I can use fast hmatrix operations. Would normalization also be a > solution for other probabilistic models? For many models, normalization isn't computationally feasible. Even for HMMs, when the tag/state space is large, I shudder to think of the overhead. The best cost I can imagine for normalizeFactor is O(log S); thus, increasing the S-dependent factor of the forward/backward algorithm's complexity from O(S^2) to O(S^2*log S). And that's at best; a naive implementation would cost O(S), making the forward/backward algorithm cubic in the size of the tag/state space! For small models that may be allowable, but for the sorts of models I work with that's an unacceptable slowdown. Even with normalization, your code would benefit from using logfloat (or some of the tricks included therein). E.g., your implementation of Math.HiddenMarkovModel.Normalized.logLikelihood will introduce a lot of unnecessary error, due to iterated use of binary (+) on Floating values. (The NC.sumElements function used in normalizeFactor may suffer the same implementation problem; but it's unclear.) The 'product' function for LogFloats performs Kahan summation in order to reduce the loss of precision due to repeated addition. (And in future versions of the library, I'm working on alternative implementations which sacrifice the single-pass property of Kahan summation in order to *completely* eliminate error of summations.) For this particular trick, you could also use Edward Kmett's "compensated" library -- Live well, ~wren From winterkoninkje at gmail.com Tue Apr 7 03:15:31 2015 From: winterkoninkje at gmail.com (wren romano) Date: Mon, 6 Apr 2015 23:15:31 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> Message-ID: I'm +1 for getting the Prelude to eventually say: class Semigroup a where mappend :: a -> a -> a mconcat :: [a] -> a (<>) = mappend infixr 6 <> class Semigroup a => Monoid a where mempty :: a instance Semigroup a => Monoid (Maybe a) where... The long path seems the most sensible way to get here with a minimum of breakage. Tis a shame it'll take so long to complete. (ObBikeshed: Honestly, I'd rather see: class Semigroup a where (<>) :: a -> a -> a concat :: [a] -> a -- or: concat :: Foldable f => f a -> a ...getting rid of the mwhatever naming scheme and avoiding taking two names for one function. The name "concat" is pretty ubiquitously used for monomorphic variants of the [a]->a type. The notable exception being Foldable.concat, which relies specifically on using the [a] semigroup for no especially interesting reason I can discern. But I'm pretty sure that ship has sailed unless we give up hope of providing a breakage-free upgrade path.) -- Live well, ~wren From winterkoninkje at gmail.com Tue Apr 7 03:51:20 2015 From: winterkoninkje at gmail.com (wren romano) Date: Mon, 6 Apr 2015 23:51:20 -0400 Subject: Proposal: Add a Semigroup-equivalent superclass of Alternative In-Reply-To: <55216B5B.1090909@ciktel.net> References: <1427631633145-5767835.post@n5.nabble.com> <55214F30.2000706@ciktel.net> <55216B5B.1090909@ciktel.net> Message-ID: On Sun, Apr 5, 2015 at 1:05 PM, Mario Bla?evi? wrote: > On 04/05/2015 12:13 PM, Edward Kmett wrote: >> >> There are many points in the design space. >> ... >> Haskell is remarkably bad at dealing with very fine-grained class >> hierarchies. > > You've blogged about this in > > https://www.fpcomplete.com/user/edwardk/editorial/procrustean-mathematics > > and I understand your concerns, even if I'm personally rooting for the > centipedes. I have to say that, both when I read the article, and re-reading > it again now, I wished for a clearer statement of the problem. Is it so > fundamental in mathematics, as you seem to imply, that no programming > language will ever be able to reconcile alternative abstractions? Or is it > only a problem with Haskell and the proposed superclass extensions, as you > suggest in I'm all for centipedes, but I agree that Haskell's type classes are pretty terrible at it. The main problems I see are Haskell's type classes (a) do not properly have laws attached to them, thus law-only classes don't work well, (b) lack a language for deriving instances from other instances, proving multiple instances equivalent, etc., and (c) require newtype hackery to have more than one instance per type. None of these are fundamentally mathematical in nature. In maths we routinely dissociate instances/structures from their carrier type, construct new structures from old ones, prove that various constructions are idempotent/inverse/coherent/etc, and so on. The problem is that Haskell's type classes don't faithfully implement the structures of this style of mathematics. For example, we have many different points in the design space, like the indexed semigroup and the non-empty Alternative. As structures, they each have different laws. Whereas many of their instances have both structures and thus satisfy both sets of laws (in addition to whatever appropriate cohesion laws), thus allowing us to equivocate between which fine structure we're referring to whenever using these instances. In addition to not being able to talk about the cohesion, Haskell doesn't let us unify the names of the structures, thus introducing a namespacing issue that doesn't arise in maths. Moreover, Haskell doesn't offer a good upgrade path to move from equivocating between two structures to settling on one or the other. Often, when we can equivocate, that means we have a huge library of combinators which work equally well for both structures; but if we stop equivocating then that forces us to duplicate (almost) the whole API, one copy for each of the fine structures we're disambiguating. Again, introducing namespacing issues. We can try to unify these APIs by making an even *more* fine-grained hierarchy, but that's just pushing the namespacing issues into the methods of the type classes, or running headlong towards law-only classes. The fundamental issue, IMO, is that type classes aren't designed to solve the problems of centipede mathematics. Type classes are designed for capturing a certain style of overloading, they aren't designed for solving namespacing issues. For centipede mathematics we need not only to be able to recognize a group of implementations as (semantically) "the same" function (? la overloading), but also to recognize a group of (semantically distinct) functions as having the same implementation (dual to overloading, "underloading"?). -- Live well, ~wren From ekmett at gmail.com Tue Apr 7 04:52:58 2015 From: ekmett at gmail.com (Edward Kmett) Date: Tue, 7 Apr 2015 00:52:58 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> Message-ID: The most likely path forward would bring in: class Semigroup a where (<>) :: a -> a -> a (... and sconcat :: NonEmpty a -> a probably hidden in a submodule to avoid bringing NonEmpty into Prelude, and times1p possibly bikeshedded to stimes1p for naming consistency, both probably exiled to Data.Semigroup) class Semigroup a => Monoid a where mappend :: a -> a -> a mappend = (<>) mempty :: a with a path towards eventually removing mappend from Monoid in 7.18+, which would get you more or less to your ObBikeshed in the long run, minus a couple of things, plus a couple of others. (and possibly a top level mtimes can then be defined in terms of stimes1p and mempty, giving peasant exponentiation for log time construction of many monoids and O(1) for idempotent ones.) As an aside: having a concat that is parameterized on Foldable on the other hand as a member of the class actually turns out to almost paradoxically prevent you from doing almost any optimizations for it. (I say almost, since because we added some members to Foldable in 7.10 this isn't quite the case any more.) Also to fold you need at least one member, so Foldable/[] is too weak. -Edward On Mon, Apr 6, 2015 at 11:15 PM, wren romano wrote: > I'm +1 for getting the Prelude to eventually say: > > class Semigroup a where > mappend :: a -> a -> a > mconcat :: [a] -> a > > (<>) = mappend > infixr 6 <> > > class Semigroup a => Monoid a where > mempty :: a > > instance Semigroup a => Monoid (Maybe a) where... > > > The long path seems the most sensible way to get here with a minimum > of breakage. Tis a shame it'll take so long to complete. > > > > > (ObBikeshed: Honestly, I'd rather see: > > class Semigroup a where > (<>) :: a -> a -> a > concat :: [a] -> a -- or: concat :: Foldable f => f a -> a > > ...getting rid of the mwhatever naming scheme and avoiding taking two > names for one function. The name "concat" is pretty ubiquitously used > for monomorphic variants of the [a]->a type. The notable exception > being Foldable.concat, which relies specifically on using the [a] > semigroup for no especially interesting reason I can discern. But I'm > pretty sure that ship has sailed unless we give up hope of providing a > breakage-free upgrade path.) > > -- > Live well, > ~wren > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Tue Apr 7 09:48:20 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Tue, 7 Apr 2015 11:48:20 +0200 (CEST) Subject: ANN: logfloat 0.13.3 In-Reply-To: References: Message-ID: On Mon, 6 Apr 2015, wren romano wrote: > For many models, normalization isn't computationally feasible. > > Even for HMMs, when the tag/state space is large, I shudder to think > of the overhead. The best cost I can imagine for normalizeFactor is > O(log S); thus, increasing the S-dependent factor of the > forward/backward algorithm's complexity from O(S^2) to O(S^2*log S). > And that's at best; a naive implementation would cost O(S), making the > forward/backward algorithm cubic in the size of the tag/state space! I apply normalization with complexity ~ S after a matrix multiplication with complexity ~ S^2, thus overall complexity remains quadratic per list element. From lemming at henning-thielemann.de Tue Apr 7 09:50:25 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Tue, 7 Apr 2015 11:50:25 +0200 (CEST) Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> Message-ID: On Mon, 6 Apr 2015, wren romano wrote: > (ObBikeshed: Honestly, I'd rather see: > > class Semigroup a where > (<>) :: a -> a -> a > concat :: [a] -> a -- or: concat :: Foldable f => f a -> a > > ...getting rid of the mwhatever naming scheme and avoiding taking two > names for one function. I also do not like the "m*" names. Btw. your 'concat' already exists as Foldable.fold, but it is not a method of Monoid or Semigroup. From me at lelf.lu Tue Apr 7 12:00:42 2015 From: me at lelf.lu (Antonio Nikishaev) Date: Tue, 07 Apr 2015 16:00:42 +0400 Subject: Proposal for a generic showIntAtBase References: Message-ID: Vikas Menon writes: > The API and behavior of showIntAtBase remains unchanged while allowing > for generic conversions not limited to Chars alone. > > Example: > ?> showIntAtBaseGeneric 26 id (:) 500 [] -- convert 500 to base26 and > provide output as a list. > [19,6] This has nothing to do with show. And it's already there h> fst (floatToDigits 26 500) [19,6] -- lelf From me at lelf.lu Tue Apr 7 15:32:12 2015 From: me at lelf.lu (Antonio Nikishaev) Date: Tue, 07 Apr 2015 19:32:12 +0400 Subject: Proposal for a generic showIntAtBase References: Message-ID: > This has nothing to do with show. > > And it's already there > > h> fst (floatToDigits 26 500) > [19,6] Oh, wait. Scratch that. You have to (++ (mantissa digits)), and it's only for RealFloat's. >> Example: >> ?> showIntAtBaseGeneric 26 id (:) 500 [] -- convert 500 to base26 and >> provide output as a list. >> [19,6] But what's wrong with just :: Integral a => Int -> a -> [Int] ? From winterkoninkje at gmail.com Tue Apr 7 17:37:55 2015 From: winterkoninkje at gmail.com (wren romano) Date: Tue, 7 Apr 2015 13:37:55 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> Message-ID: On Tue, Apr 7, 2015 at 12:52 AM, Edward Kmett wrote: > The most likely path forward would bring in: > > class Semigroup a where > (<>) :: a -> a -> a > (... and sconcat :: NonEmpty a -> a probably hidden in a submodule to > avoid bringing NonEmpty into Prelude, and times1p possibly bikeshedded to > stimes1p for naming consistency, both probably exiled to Data.Semigroup) Whoops! Yes, that's the type I meant for concatenation ::chagrin:: -- Live well, ~wren From byorgey at gmail.com Thu Apr 9 14:00:53 2015 From: byorgey at gmail.com (Brent Yorgey) Date: Thu, 09 Apr 2015 14:00:53 +0000 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> Message-ID: As is probably well-known, I am definitely +1 on this. I don't have strong opinions about which particular path we take to get there. On Tue, Apr 7, 2015 at 1:37 PM wren romano wrote: > On Tue, Apr 7, 2015 at 12:52 AM, Edward Kmett wrote: > > The most likely path forward would bring in: > > > > class Semigroup a where > > (<>) :: a -> a -> a > > (... and sconcat :: NonEmpty a -> a probably hidden in a submodule to > > avoid bringing NonEmpty into Prelude, and times1p possibly bikeshedded to > > stimes1p for naming consistency, both probably exiled to Data.Semigroup) > > Whoops! Yes, that's the type I meant for concatenation ::chagrin:: > > -- > Live well, > ~wren > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From petr.mvd at gmail.com Fri Apr 10 14:47:04 2015 From: petr.mvd at gmail.com (=?UTF-8?B?UGV0ciBQdWRsw6Fr?=) Date: Fri, 10 Apr 2015 14:47:04 +0000 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: <03FDCB37-EEC8-4746-B46D-FB6073936BCD@inconsistent.nl> References: <1427631633145-5767835.post@n5.nabble.com> <20150330031633.GA28985@mintha> <03FDCB37-EEC8-4746-B46D-FB6073936BCD@inconsistent.nl> Message-ID: Franti?ek Farka [1] worked in detail on a proposal that would make such refactorings painless, see *Maintainable type classes for Haskell* [2] Cheers, Petr [1] http://staff.computing.dundee.ac.uk/frantisekfarka/ [2] http://staff.computing.dundee.ac.uk/frantisekfarka/publications.html po 30. 3. 2015 v 11:24 odes?latel Merijn Verstraaten napsal: > -2 from me. > > Not because I oppose Semigroup as a superclass of Monoid, but because of > brittle migration path. > > I would much rather put the resurrection of DefaultSuperclassInstances > [1], IntrinsicSuperclasses [2], or some new proposal on the roadmap that > would allow us to more easily refactor and update the typeclass hierarchy > without breaking everything all the time. > > Cheers, > Merijn > > [1] - https://ghc.haskell.org/trac/ghc/wiki/DefaultSuperclassInstances > [2] - https://ghc.haskell.org/trac/ghc/wiki/IntrinsicSuperclasses > > On 30 Mar 2015, at 5:39, John Alfred Nathanael Chee > wrote: > > > > Jeremy, > > > > Do you propose: > > > > Monoid a => Monoid (Maybe a) > > > > be changed to: > > > > Semigroup a => Monoid (Maybe a) > > > > as the documentation indicates? > > > > +1, but I think there are some technicalities that I think would benefit > from a more concrete proposal including as a patch or hackage analysis. > > > > On Sun, Mar 29, 2015 at 8:16 PM, M Farkas-Dyck > wrote: > > On 29/03/2015 at 05:20:33 -0700, Jeremy wrote: > > > 1. GHC 7.12 will include Semigroup and NonEmpty in base. > > > > +1 for Semigroup at least. > > > > NonEmpty is simply the cofree comonad of Maybe, so I think we ought to > define it either as such or to be compatibly redefinitile as such, e.g. > > > > now: > > data NonEmpty a = a .: Maybe (NonEmpty a) > > > > so potentially later: > > data Cofree f a = a .: f (Cofree f a) > > type NonEmpty = Cofree Maybe > > > > as otherwise we shall have various code using nonsame isomorphic types > which one must convert or coerce between for no good reason. > > > > +1 for NonEmpty if so defined, -1 otherwise. > > > > > 2. GHC >7.12 will define Monoid as a subclass of Semigroup. > > > > +1 > > > > On 29/03/2015 at 11:23:19 -0400, David Feuer wrote: > > > I guess I should get a dog in the fight?I think <> should be the > Semigroup method. > > > > +1 > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > > > > > > -- > > Love in Jesus Christ, John Alfred Nathanael Chee > > http://www.biblegateway.com/ > > http://web.cecs.pdx.edu/~chee/ > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander at plaimi.net Sat Apr 11 12:43:00 2015 From: alexander at plaimi.net (Alexander Berntsen) Date: Sat, 11 Apr 2015 14:43:00 +0200 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: <1427631633145-5767835.post@n5.nabble.com> References: <1427631633145-5767835.post@n5.nabble.com> Message-ID: <552916D4.9070206@plaimi.net> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 +1. P.S. Another rationale (that tends to sway me) is that this is The Right Thing. :) - -- Alexander alexander at plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iF4EAREIAAYFAlUpFtMACgkQRtClrXBQc7U4qwEAgedg673GwrLr6U9vQ49cq4ne Gr7AYex93vevJNi04XsA/2KsAoXJMPfYgV7D78ZdBt2PAJys5mZrckTsN0tB6Oja =AHA4 -----END PGP SIGNATURE----- From aditya.siram at gmail.com Sun Apr 12 23:52:30 2015 From: aditya.siram at gmail.com (aditya siram) Date: Sun, 12 Apr 2015 18:52:30 -0500 Subject: [Announcement] FLTKHS - Bindings to the FLTK GUI Toolkit Message-ID: I'm pleased to announce the first release of Haskell bindings [1] to the FLTK GUI [2] toolkit. It now works smoothly on Windows (64-bit), Linux and Mac allowing you to create truly cross-platform native GUI applications in pure Haskell and deploy statically linked executables with no dependencies. Most of the FLTK API is covered except for a few minor widgets which I plan to get to in the next release. Motivation behind the package and installation instructions are found in the Haddocks [3]. And to get you started it ships with a number of demos. If you have any issues please report them on the Github [4] page. I'd also love any other feedback so feel free to comment here or email me at the address listed on the Hackage [5] page. Hope you enjoy! [1] https://hackage.haskell.org/package/fltkhs-0.1.0.2 [2] http://fltk.org [3] https://hackage.haskell.org/package/fltkhs-0.1.0.2/docs/Graphics-UI-FLTK-LowLevel-FLTKHS.html [4] http://github.com/deech/fltkhs [5] https://hackage.haskell.org/package/fltkhs-0.1.0.2 -------------- next part -------------- An HTML attachment was scrubbed... URL: From mwm at mired.org Tue Apr 14 17:05:32 2015 From: mwm at mired.org (Mike Meyer) Date: Tue, 14 Apr 2015 12:05:32 -0500 Subject: Bed & Breakfast maintainer? Message-ID: Anyone out there maintaining (or willing to take over) the bed-and-breakfast package? 0.4.3 (the latest release) doesn't compile with 7.8 because of the changes to Typeable. The git repo has fixes for this in it, along with some other stuff, but that's nearly a year old, and hasn't been released yet. My requests to the author & maintainer (Julian Fleischer < julian.fleischer at fu-berlin.de>) have gone unanswered. -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Tue Apr 14 17:14:10 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Tue, 14 Apr 2015 19:14:10 +0200 (CEST) Subject: Bed & Breakfast maintainer? In-Reply-To: References: Message-ID: On Tue, 14 Apr 2015, Mike Meyer wrote: > My requests to the author & maintainer (Julian Fleischer > ) have gone unanswered. Have you also tried: http://www.scravy.de/ https://github.com/scravy ? Btw. I think hmatrix is better for doing serious linear algebra in Haskell. From mgsloan at gmail.com Tue Apr 14 18:38:56 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 14 Apr 2015 11:38:56 -0700 Subject: Proposal: Add exception info Message-ID: Control.Exception currently lacks a good way to supply extra information along with exceptions. For example, exceptions could be thrown along with their callstack[1] or implicit stack[2], but we have no generic way to include this information with exceptions. Proposed Solution ================= The proposed solution is to add a list of `SomeExceptionInfo` to the `SomeException` datatype. This list stores additional information about the exception. These `ExceptionInfo` instances use a mechanism which is pretty much identical to the dynamic way the `Exception` type works: data SomeException = forall e . Exception e => SomeExceptionWithInfo e [SomeExceptionInfo] data SomeExceptionInfo = forall a . ExceptionInfo a => SomeExceptionInfo a class Typeable a => ExceptionInfo a where displayExceptionInfo :: a -> String addExceptionInfo :: (ExceptionInfo a, Exception e) => a -> e -> SomeException addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = SomeExceptionWithInfo e (SomeExceptionInfo x : xs) `ExceptionInfo` lacks the to / from functions that `Exception` has, because I don't see much point in supporting a hierarchy for exception info. The `Typeable` superclass constraint supplies the necessary casting. `SomeExceptionInfo` could validly instead just use the constraint `(Typeable a, Show a)`. However, I believe it's good to have a new class for this so that: * The user can specify a custom `displayExceptionInfo` implementation, for when this extra info is presented to the user. This function would be invoked by the `show` implementation for `SomeException`. * Types need to opt-in to be usable with `SomeExceptionInfo`. Similarly to exceptions, I imagine that a type with a `ExceptionInfo` instance won't be used for anything but acting as such an annotation. Having a class for this allows you to ask GHCI about all in-scope exception info types via `:info ExceptionInfo`. Backwards Compatibility ======================= GHC 7.10 adds support for bidirectional pattern synonyms. This means that this change could be made without breaking code: pattern SomeException x <- SomeExceptionWithInfo x _ where SomeException x = SomeExceptionWithInfo x [] Note that consumers of this do not need to enable `-XPatternSynonyms`. Applications ============ Callstacks ---------- As mentioned at the beginning, this can be used to add callstacks to exceptions: newtype ExceptionCallStack = ExceptionCallStack { unExceptionCallStack :: [String] } deriving Typeable instance ExceptionInfo ExceptionCallStack where displayExceptionInfo = unlines . unExceptionCallStack throwIOWithStack :: Exception e => e -> IO a throwIOWithStack e = do stack <- currentCallStack if null stack then throwIO e else throwIO (addExceptionInfo (ExceptionCallStack stack) e) I see little downside for making something like this the default implementation `throwIO`. Each rethrowing of the `SomeException` would add an additional stacktrace to its annotation, much like the output of `+RTS -xc`. Unlike this debug output, though, the stacktraces would be associated with the exception, rather than just listing locations that exceptions were thrown. This makes it tractable to debug exceptions that occur in concurrent programs, or in programs which frequently throw exceptions during normal functioning. Throwing Exceptions in Handlers ------------------------------- Example: main = throwIO InformativeErrorMessage `finally` throwIO ObscureCleanupIssue While `InformativeErrorMessage` got thrown, the user doesn't see it, since `ObscureCleanupIssue` is thrown instead. This causes a few issues: 1. If the exception is handled by the default handler and yielded to the user, then the more informative error is lost. 2. Callers who expect to catch the "Informative error message" won't run their handlers for this exception type. Problem 1 can now easily be resolved by adding some info to the exception: data ExceptionCause = ExceptionCause { unExceptionCause :: SomeException } deriving Typeable instance ExceptionInfo ExceptionCause where displayExceptionInfo fe = "thrown while handling " ++ displayException (unExceptionCause fe) catch :: Exception e => IO a -> (e -> IO a) -> IO a catch f g = f `oldCatch` handler where handler ex = g ex `oldCatch` \(ex' :: SomeException) -> throwIO (addExceptionInfo info ex') where info = ExceptionCause (toException ex) This implementation of `catch` is written in a backwards-compatible way, such that the exception thrown during finalization is still the one that gets rethrown. The "original" exception is recorded in the added info. This is the same approach used by Python 3's `__context__` attribute[3]. This was brought to my attention in a post by Mike Meyer[4], in a thread about having bracket not suppress the original exception[5]. This doesn't directly resolve issue #2, due to this backwards compatibility. With the earlier example, a `catch` handler for `InformativeErrorMessage` won't be invoked, because it isn't the exception being rethrown. This can be resolved by having a variant of catch which instead throws the original exception. This might be a good default for finalization handlers like `bracket` and `finally`. Asynchronous Exceptions ----------------------- Currently, the only reliable way to catch exceptions, ignoring async exceptions, is to fork a new thread. This is the approach used by the enclosed-exceptions[6] package. I think it's quite ugly that we need to go to such lengths due to the lack of one bit of information about the exception! This would resolve ghc trac #5902[7]. base-4.7 added the `SomeAsyncException` type, but this doesn't enforce anything. Any exception can be thrown as a sync or async exception. Instead, we ought to have a reliable way to know if an exception is synchronous or asynchronous. Here's what this would look like: data IsAsync = IsAsync deriving (Typeable, Show) instance ExceptionInfo IsAsync where displayExceptionInfo IsAsync = "thrown asynchronously" throwTo :: Exception e => ThreadId -> e -> IO () throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync The details of this get a bit tricky: What happens if `throwIO` is used to rethrow a `SomeException` which has this `IsAsync` flag set? I'm going to leave out my thoughts on this for now as the interactions between unsafePerformIO and the concept of "rethrowing" async exceptions. Such details are explained in a post by Edsko de Vries[8] and ghc trac #2558[9]. Issue: fromException loses info =============================== I can think of one main non-ideal aspect of this proposal: Currently, the `toException` and `fromException` methods usually form a prism. In other words, when `fromException` yields a `Just`, you should get the same `SomeException` when using `toException` on that value. For example, fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex is equivalent to fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex However, with exception info added to just `SomeException`, and no changes to existing `Exception` instances, this doesn't hold. Exceptions caught as a specific exception type get rethrown with less information. One resolution to this is be to add `[SomeExceptionInfo]` as a field to existing `Exception` instances. This would require the use of non-default implementations of the `toException` and `fromException` instances. Another approach is to have variants of `catch` and `throw` which also pass around the `[SomeExceptionInfo]`. [1] https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack [2] https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations [3] https://www.python.org/dev/peps/pep-3134/ [4] https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html [5] https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html [6] https://hackage.haskell.org/package/enclosed-exceptions [7] https://ghc.haskell.org/trac/ghc/ticket/5902 [8] http://www.edsko.net/2013/06/11/throwTo/ [9] https://ghc.haskell.org/trac/ghc/ticket/2558 -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam at bergmark.nl Tue Apr 14 20:30:11 2015 From: adam at bergmark.nl (Adam Bergmark) Date: Tue, 14 Apr 2015 22:30:11 +0200 Subject: Bed & Breakfast maintainer? In-Reply-To: References: Message-ID: Hi Mike, See section 2 of https://wiki.haskell.org/Taking_over_a_package With the public e-mail+CC in place you can then either email the hackage admins after two weeks or immediately open a ticket on https://github.com/haskell-infra/hackage-trustees/issues , assuming no response from the maintainer admins can either give you maintainership (that you can give to someone else if you'd like), or they can do a non-maintainer upload with the fixes. Cheers, Adam On Tue, Apr 14, 2015 at 7:14 PM, Henning Thielemann < lemming at henning-thielemann.de> wrote: > > On Tue, 14 Apr 2015, Mike Meyer wrote: > > My requests to the author & maintainer (Julian Fleischer < >> julian.fleischer at fu-berlin.de>) have gone unanswered. >> > > Have you also tried: > http://www.scravy.de/ > https://github.com/scravy > ? > > Btw. I think hmatrix is better for doing serious linear algebra in Haskell. > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From douglas.mcclean at gmail.com Wed Apr 15 00:43:17 2015 From: douglas.mcclean at gmail.com (Douglas McClean) Date: Tue, 14 Apr 2015 20:43:17 -0400 Subject: Floating and Data.Fixed Message-ID: Hello libraries list, (Warning: this whole message may be a waste of time, you may wish to skip it.) I'd like to inquire about the possibility of a Floating instance for Data.Fixed. (Unfortunately, not knowing of the existence of this list or the appropriate procedure, I created a trac ticket to ask about this, because that was the only forum I knew of. It's https://ghc.haskell.org/trac/ghc/ticket/10297. Sorry.) The original idea was along these lines: lift :: (HasResolution a) => (Double -> Double) -> Fixed a -> Fixed a lift f = realToFrac . f . realToFrac instance (HasResolution a) => Floating (Fixed a) where pi = realToFrac pi sin = lift sin -- etc, similar lift2 function for (**), logBase This allows the use of transcendental functions on Fixed values. Conceptually, transcendental functions on fixed point values aren't problematic, and are actually pretty widely used in certain gaming/simulation/signal processing applications. I've since learned that this may not be a good idea. A commenter (Scott Turner) on the haskell-cafe mailing list astutely raised the issue that because Data.Fixed uses the arbitrary-size Integer type, it's impossible to correctly compute these functions for all possible Fixed values without an arbitrary precision implementation, simply converting through Double like this won't always work. Sometimes it can be unclear where to draw the line and "stop worrying" about such issues. However, in this case I think it is a good objection, and that a better solution may be to work on advancing Data.Fixed.Binary or a similar library as a home for this functionality, where the size of the values is statically bounded. This has the advantage of also being outside the scope of the base libraries, and thus easier to modify due to the reduced impact. Unfortunately I learned this was probably unworthy of this list's attention after having already filed the trac ticket. Unless anyone disagrees and thinks this would be worthwhile, I will close that ticket tomorrow with a note saying where I'm redirecting the effort. -Doug McClean -------------- next part -------------- An HTML attachment was scrubbed... URL: From davean at xkcd.com Wed Apr 15 02:29:21 2015 From: davean at xkcd.com (davean) Date: Tue, 14 Apr 2015 22:29:21 -0400 Subject: Floating and Data.Fixed In-Reply-To: References: Message-ID: The option you seem to be left unsaid is implementing them correctly. A lot of the reason for Data.Fixed is you actually require the accuracy they claim. But these functions aren't magic, they can be calculated to a given accuracy from their power series approximations, among several other good methods which are easy to implement and several more methods which are faster. It would seem, if one were using Data.Fixed, that is what they should want. It sounds like you might just want more accurate approximations, like http://hackage.haskell.org/package/compensated would offer and not actually fixed point. If that isn't more what you're looking for, I'd be interested in what your use case is for inaccurate fixed point computations was. (Not to imply its bad, I can think of a few common scenarios where fairly inaccurate intermediary results lead to extremely accurate results in the end) -davean On Tue, Apr 14, 2015 at 8:43 PM, Douglas McClean wrote: > Hello libraries list, > > (Warning: this whole message may be a waste of time, you may wish to skip > it.) > > I'd like to inquire about the possibility of a Floating instance for > Data.Fixed. (Unfortunately, not knowing of the existence of this list or > the appropriate procedure, I created a trac ticket to ask about this, > because that was the only forum I knew of. It's > https://ghc.haskell.org/trac/ghc/ticket/10297. Sorry.) > > The original idea was along these lines: > > lift :: (HasResolution a) => (Double -> Double) -> Fixed a -> Fixed a > lift f = realToFrac . f . realToFrac > > instance (HasResolution a) => Floating (Fixed a) where > pi = realToFrac pi > sin = lift sin > -- etc, similar lift2 function for (**), logBase > > This allows the use of transcendental functions on Fixed values. > Conceptually, transcendental functions on fixed point values aren't > problematic, and are actually pretty widely used in certain > gaming/simulation/signal processing applications. > > I've since learned that this may not be a good idea. A commenter (Scott > Turner) on the haskell-cafe mailing list astutely raised the issue that > because Data.Fixed uses the arbitrary-size Integer type, it's impossible to > correctly compute these functions for all possible Fixed values without an > arbitrary precision implementation, simply converting through Double like > this won't always work. > > Sometimes it can be unclear where to draw the line and "stop worrying" > about such issues. However, in this case I think it is a good objection, > and that a better solution may be to work on advancing Data.Fixed.Binary or > a similar library as a home for this functionality, where the size of the > values is statically bounded. This has the advantage of also being outside > the scope of the base libraries, and thus easier to modify due to the > reduced impact. > > Unfortunately I learned this was probably unworthy of this list's > attention after having already filed the trac ticket. > > Unless anyone disagrees and thinks this would be worthwhile, I will close > that ticket tomorrow with a note saying where I'm redirecting the effort. > > > -Doug McClean > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed Apr 15 02:55:34 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Tue, 14 Apr 2015 22:55:34 -0400 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Hey Michael, I actually proposed something along these lines that got OK'd by libraries early this past fall, the main challenge we hit was actually doing the enginering to add the stack traces to exceptions! theres some nasty module cycles in base that happen when you try to weave things around so that the standard error "message here" call includes some stack trace info. Have you tried to do that simple starter patch to base? Chris Allen and I spent like 2 days trying to get it to work and just gave up because of the cycles. We (and others) would probably love some headway on that front. Theres also some in progress work to use the dwarf debugging info data in >7.10 to provide useful stack traces in the default builds for GHC afaik, 'cause the stack trace functionality you're pointing at currenlty only work on profiled builds cheers -Carter On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan wrote: > Control.Exception currently lacks a good way to supply extra > information along with exceptions. For example, exceptions could be > thrown along with their callstack[1] or implicit stack[2], but we have > no generic way to include this information with exceptions. > > Proposed Solution > ================= > > The proposed solution is to add a list of `SomeExceptionInfo` to the > `SomeException` datatype. This list stores additional information > about the exception. These `ExceptionInfo` instances use a mechanism > which is pretty much identical to the dynamic way the `Exception` type > works: > > data SomeException = forall e . Exception e => > SomeExceptionWithInfo e [SomeExceptionInfo] > > data SomeExceptionInfo = forall a . ExceptionInfo a => > SomeExceptionInfo a > > class Typeable a => ExceptionInfo a where > displayExceptionInfo :: a -> String > > addExceptionInfo > :: (ExceptionInfo a, Exception e) > => a -> e -> SomeException > addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = > SomeExceptionWithInfo e (SomeExceptionInfo x : xs) > > `ExceptionInfo` lacks the to / from functions that `Exception` has, > because I don't see much point in supporting a hierarchy for exception > info. The `Typeable` superclass constraint supplies the necessary > casting. > > `SomeExceptionInfo` could validly instead just use the constraint > `(Typeable a, Show a)`. However, I believe it's good to have a new > class for this so that: > > * The user can specify a custom `displayExceptionInfo` > implementation, for when this extra info is presented to the user. > This function would be invoked by the `show` implementation for > `SomeException`. > > * Types need to opt-in to be usable with `SomeExceptionInfo`. > Similarly to exceptions, I imagine that a type with a > `ExceptionInfo` instance won't be used for anything but acting as > such an annotation. Having a class for this allows you to ask GHCI > about all in-scope exception info types via `:info ExceptionInfo`. > > Backwards Compatibility > ======================= > > GHC 7.10 adds support for bidirectional pattern synonyms. This means > that this change could be made without breaking code: > > pattern SomeException x <- SomeExceptionWithInfo x _ where > SomeException x = SomeExceptionWithInfo x [] > > Note that consumers of this do not need to enable `-XPatternSynonyms`. > > Applications > ============ > > Callstacks > ---------- > > As mentioned at the beginning, this can be used to add callstacks to > exceptions: > > newtype ExceptionCallStack = > ExceptionCallStack { unExceptionCallStack :: [String] } > deriving Typeable > > instance ExceptionInfo ExceptionCallStack where > displayExceptionInfo = unlines . unExceptionCallStack > > throwIOWithStack :: Exception e => e -> IO a > throwIOWithStack e = do > stack <- currentCallStack > if null stack > then throwIO e > else throwIO (addExceptionInfo (ExceptionCallStack stack) e) > > I see little downside for making something like this the default > implementation `throwIO`. Each rethrowing of the `SomeException` > would add an additional stacktrace to its annotation, much like the > output of `+RTS -xc`. Unlike this debug output, though, the > stacktraces would be associated with the exception, rather than just > listing locations that exceptions were thrown. This makes it > tractable to debug exceptions that occur in concurrent programs, or in > programs which frequently throw exceptions during normal functioning. > > Throwing Exceptions in Handlers > ------------------------------- > > Example: > > main = > throwIO InformativeErrorMessage `finally` > throwIO ObscureCleanupIssue > > While `InformativeErrorMessage` got thrown, the user doesn't see it, > since `ObscureCleanupIssue` is thrown instead. This causes a few > issues: > > 1. If the exception is handled by the default handler and yielded to > the user, then the more informative error is lost. > > 2. Callers who expect to catch the "Informative error message" won't > run their handlers for this exception type. > > Problem 1 can now easily be resolved by adding some info to the > exception: > > data ExceptionCause = ExceptionCause > { unExceptionCause :: SomeException } > deriving Typeable > > instance ExceptionInfo ExceptionCause where > displayExceptionInfo fe = > "thrown while handling " ++ > displayException (unExceptionCause fe) > > catch :: Exception e => IO a -> (e -> IO a) -> IO a > catch f g = f `oldCatch` handler > where > handler ex = g ex `oldCatch` \(ex' :: SomeException) -> > throwIO (addExceptionInfo info ex') > where > info = ExceptionCause (toException ex) > > This implementation of `catch` is written in a backwards-compatible > way, such that the exception thrown during finalization is still the > one that gets rethrown. The "original" exception is recorded in the > added info. This is the same approach used by Python 3's > `__context__` attribute[3]. This was brought to my attention in a > post by Mike Meyer[4], in a thread about having bracket not suppress > the original exception[5]. > > This doesn't directly resolve issue #2, due to this backwards > compatibility. With the earlier example, a `catch` handler for > `InformativeErrorMessage` won't be invoked, because it isn't the > exception being rethrown. This can be resolved by having a variant of > catch which instead throws the original exception. This might be a > good default for finalization handlers like `bracket` and `finally`. > > Asynchronous Exceptions > ----------------------- > > Currently, the only reliable way to catch exceptions, ignoring async > exceptions, is to fork a new thread. This is the approach used by the > enclosed-exceptions[6] package. I think it's quite ugly that we need > to go to such lengths due to the lack of one bit of information about > the exception! This would resolve ghc trac #5902[7]. > > base-4.7 added the `SomeAsyncException` type, but this doesn't enforce > anything. Any exception can be thrown as a sync or async exception. > Instead, we ought to have a reliable way to know if an exception is > synchronous or asynchronous. Here's what this would look like: > > data IsAsync = IsAsync > deriving (Typeable, Show) > > instance ExceptionInfo IsAsync where > displayExceptionInfo IsAsync = "thrown asynchronously" > > throwTo :: Exception e => ThreadId -> e -> IO () > throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync > > The details of this get a bit tricky: What happens if `throwIO` is > used to rethrow a `SomeException` which has this `IsAsync` flag set? > I'm going to leave out my thoughts on this for now as the interactions > between unsafePerformIO and the concept of "rethrowing" async > exceptions. Such details are explained in a post by Edsko de Vries[8] > and ghc trac #2558[9]. > > Issue: fromException loses info > =============================== > > I can think of one main non-ideal aspect of this proposal: > > Currently, the `toException` and `fromException` methods usually form > a prism. In other words, when `fromException` yields a `Just`, you > should get the same `SomeException` when using `toException` on that > value. > > For example, > > fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex > > is equivalent to > > fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex > > However, with exception info added to just `SomeException`, and no > changes to existing `Exception` instances, this > doesn't hold. Exceptions caught as a specific exception type get > rethrown with less information. > > One resolution to this is be to add `[SomeExceptionInfo]` as a field > to existing `Exception` instances. This would require the use of > non-default implementations of the `toException` and `fromException` > instances. > > Another approach is to have variants of `catch` and `throw` which also > pass around the `[SomeExceptionInfo]`. > > [1] > https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack > [2] > https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations > [3] https://www.python.org/dev/peps/pep-3134/ > [4] https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html > [5] https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html > [6] https://hackage.haskell.org/package/enclosed-exceptions > [7] https://ghc.haskell.org/trac/ghc/ticket/5902 > [8] http://www.edsko.net/2013/06/11/throwTo/ > [9] https://ghc.haskell.org/trac/ghc/ticket/2558 > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Wed Apr 15 04:22:54 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 14 Apr 2015 21:22:54 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Hi Carter! Interesting! This thread, right? https://mail.haskell.org/pipermail/libraries/2014-December/024429.html I haven't tried this as a patch to base, but I'm certain that the core of the proposal has no extra dependencies. Note that the proposal isn't about stack traces in particular - that's just one application of being able to throw exceptions with extra information. Even if `throwTo` isn't modified to throw exceptions with stack traces, this functionality could be provided outside of `Control.Exception` (though, that does seem like the right place to put it). I'm surprised that the circularity was so problematic, though. Why isn't it sufficient to have an hs-boot file for `GHC.Stack`, which exports `currentCallStack`? -Michael On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > Hey Michael, > I actually proposed something along these lines that got OK'd by libraries > early this past fall, the main challenge we hit was actually doing the > enginering to add the stack traces to exceptions! theres some nasty module > cycles in base that happen when you try to weave things around so that the > standard error "message here" call includes some stack trace info. Have you > tried to do that simple starter patch to base? > > Chris Allen and I spent like 2 days trying to get it to work and just gave > up because of the cycles. We (and others) would probably love some headway > on that front. > > Theres also some in progress work to use the dwarf debugging info data in > >7.10 to provide useful stack traces in the default builds for GHC afaik, > 'cause the stack trace functionality you're pointing at currenlty only work > on profiled builds > > cheers > -Carter > > On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan wrote: > >> Control.Exception currently lacks a good way to supply extra >> information along with exceptions. For example, exceptions could be >> thrown along with their callstack[1] or implicit stack[2], but we have >> no generic way to include this information with exceptions. >> >> Proposed Solution >> ================= >> >> The proposed solution is to add a list of `SomeExceptionInfo` to the >> `SomeException` datatype. This list stores additional information >> about the exception. These `ExceptionInfo` instances use a mechanism >> which is pretty much identical to the dynamic way the `Exception` type >> works: >> >> data SomeException = forall e . Exception e => >> SomeExceptionWithInfo e [SomeExceptionInfo] >> >> data SomeExceptionInfo = forall a . ExceptionInfo a => >> SomeExceptionInfo a >> >> class Typeable a => ExceptionInfo a where >> displayExceptionInfo :: a -> String >> >> addExceptionInfo >> :: (ExceptionInfo a, Exception e) >> => a -> e -> SomeException >> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >> >> `ExceptionInfo` lacks the to / from functions that `Exception` has, >> because I don't see much point in supporting a hierarchy for exception >> info. The `Typeable` superclass constraint supplies the necessary >> casting. >> >> `SomeExceptionInfo` could validly instead just use the constraint >> `(Typeable a, Show a)`. However, I believe it's good to have a new >> class for this so that: >> >> * The user can specify a custom `displayExceptionInfo` >> implementation, for when this extra info is presented to the user. >> This function would be invoked by the `show` implementation for >> `SomeException`. >> >> * Types need to opt-in to be usable with `SomeExceptionInfo`. >> Similarly to exceptions, I imagine that a type with a >> `ExceptionInfo` instance won't be used for anything but acting as >> such an annotation. Having a class for this allows you to ask GHCI >> about all in-scope exception info types via `:info ExceptionInfo`. >> >> Backwards Compatibility >> ======================= >> >> GHC 7.10 adds support for bidirectional pattern synonyms. This means >> that this change could be made without breaking code: >> >> pattern SomeException x <- SomeExceptionWithInfo x _ where >> SomeException x = SomeExceptionWithInfo x [] >> >> Note that consumers of this do not need to enable `-XPatternSynonyms`. >> >> Applications >> ============ >> >> Callstacks >> ---------- >> >> As mentioned at the beginning, this can be used to add callstacks to >> exceptions: >> >> newtype ExceptionCallStack = >> ExceptionCallStack { unExceptionCallStack :: [String] } >> deriving Typeable >> >> instance ExceptionInfo ExceptionCallStack where >> displayExceptionInfo = unlines . unExceptionCallStack >> >> throwIOWithStack :: Exception e => e -> IO a >> throwIOWithStack e = do >> stack <- currentCallStack >> if null stack >> then throwIO e >> else throwIO (addExceptionInfo (ExceptionCallStack stack) e) >> >> I see little downside for making something like this the default >> implementation `throwIO`. Each rethrowing of the `SomeException` >> would add an additional stacktrace to its annotation, much like the >> output of `+RTS -xc`. Unlike this debug output, though, the >> stacktraces would be associated with the exception, rather than just >> listing locations that exceptions were thrown. This makes it >> tractable to debug exceptions that occur in concurrent programs, or in >> programs which frequently throw exceptions during normal functioning. >> >> Throwing Exceptions in Handlers >> ------------------------------- >> >> Example: >> >> main = >> throwIO InformativeErrorMessage `finally` >> throwIO ObscureCleanupIssue >> >> While `InformativeErrorMessage` got thrown, the user doesn't see it, >> since `ObscureCleanupIssue` is thrown instead. This causes a few >> issues: >> >> 1. If the exception is handled by the default handler and yielded to >> the user, then the more informative error is lost. >> >> 2. Callers who expect to catch the "Informative error message" won't >> run their handlers for this exception type. >> >> Problem 1 can now easily be resolved by adding some info to the >> exception: >> >> data ExceptionCause = ExceptionCause >> { unExceptionCause :: SomeException } >> deriving Typeable >> >> instance ExceptionInfo ExceptionCause where >> displayExceptionInfo fe = >> "thrown while handling " ++ >> displayException (unExceptionCause fe) >> >> catch :: Exception e => IO a -> (e -> IO a) -> IO a >> catch f g = f `oldCatch` handler >> where >> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >> throwIO (addExceptionInfo info ex') >> where >> info = ExceptionCause (toException ex) >> >> This implementation of `catch` is written in a backwards-compatible >> way, such that the exception thrown during finalization is still the >> one that gets rethrown. The "original" exception is recorded in the >> added info. This is the same approach used by Python 3's >> `__context__` attribute[3]. This was brought to my attention in a >> post by Mike Meyer[4], in a thread about having bracket not suppress >> the original exception[5]. >> >> This doesn't directly resolve issue #2, due to this backwards >> compatibility. With the earlier example, a `catch` handler for >> `InformativeErrorMessage` won't be invoked, because it isn't the >> exception being rethrown. This can be resolved by having a variant of >> catch which instead throws the original exception. This might be a >> good default for finalization handlers like `bracket` and `finally`. >> >> Asynchronous Exceptions >> ----------------------- >> >> Currently, the only reliable way to catch exceptions, ignoring async >> exceptions, is to fork a new thread. This is the approach used by the >> enclosed-exceptions[6] package. I think it's quite ugly that we need >> to go to such lengths due to the lack of one bit of information about >> the exception! This would resolve ghc trac #5902[7]. >> >> base-4.7 added the `SomeAsyncException` type, but this doesn't enforce >> anything. Any exception can be thrown as a sync or async exception. >> Instead, we ought to have a reliable way to know if an exception is >> synchronous or asynchronous. Here's what this would look like: >> >> data IsAsync = IsAsync >> deriving (Typeable, Show) >> >> instance ExceptionInfo IsAsync where >> displayExceptionInfo IsAsync = "thrown asynchronously" >> >> throwTo :: Exception e => ThreadId -> e -> IO () >> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >> >> The details of this get a bit tricky: What happens if `throwIO` is >> used to rethrow a `SomeException` which has this `IsAsync` flag set? >> I'm going to leave out my thoughts on this for now as the interactions >> between unsafePerformIO and the concept of "rethrowing" async >> exceptions. Such details are explained in a post by Edsko de Vries[8] >> and ghc trac #2558[9]. >> >> Issue: fromException loses info >> =============================== >> >> I can think of one main non-ideal aspect of this proposal: >> >> Currently, the `toException` and `fromException` methods usually form >> a prism. In other words, when `fromException` yields a `Just`, you >> should get the same `SomeException` when using `toException` on that >> value. >> >> For example, >> >> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex >> >> is equivalent to >> >> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >> >> However, with exception info added to just `SomeException`, and no >> changes to existing `Exception` instances, this >> doesn't hold. Exceptions caught as a specific exception type get >> rethrown with less information. >> >> One resolution to this is be to add `[SomeExceptionInfo]` as a field >> to existing `Exception` instances. This would require the use of >> non-default implementations of the `toException` and `fromException` >> instances. >> >> Another approach is to have variants of `catch` and `throw` which also >> pass around the `[SomeExceptionInfo]`. >> >> [1] >> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >> [2] >> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >> [3] https://www.python.org/dev/peps/pep-3134/ >> [4] https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >> [5] https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >> [6] https://hackage.haskell.org/package/enclosed-exceptions >> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >> [8] http://www.edsko.net/2013/06/11/throwTo/ >> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mwm at mired.org Wed Apr 15 18:52:28 2015 From: mwm at mired.org (Mike Meyer) Date: Wed, 15 Apr 2015 13:52:28 -0500 Subject: bed & breakfast library update? Message-ID: I've asked a couple of times over the last eight moths for an update of this library that would compile on 7.8 to be published, and gotten no response. If you're not able or interested in maintaining this library any longer, please let the community know so that someone else can take over those duties. If you can't or don't respond, I'll have to assume you're no longer able to, and see about getting another maintainer. Thank you, Mike -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Thu Apr 16 15:26:16 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Thu, 16 Apr 2015 11:26:16 -0400 Subject: Bed & Breakfast maintainer? In-Reply-To: References: Message-ID: <4E9DFC16-912B-45C2-9D1C-8F95A779B8EA@gmail.com> it looks like the author is active on github, so someone should try reaching out to him for > On Tue, Apr 14, 2015 at 4:30 PM, Adam Bergmark wrote: > Hi Mike, > > See section 2 of https://wiki.haskell.org/Taking_over_a_package > > With the public e-mail+CC in place you can then either email the hackage admins after two weeks or immediately open a ticket on https://github.com/haskell-infra/hackage-trustees/issues , assuming no response from the maintainer admins can either give you maintainership (that you can give to someone else if you'd like), or they can do a non-maintainer upload with the fixes. > > Cheers, > Adam > > >> On Tue, Apr 14, 2015 at 7:14 PM, Henning Thielemann wrote: >> >> On Tue, 14 Apr 2015, Mike Meyer wrote: >> >>> My requests to the author & maintainer (Julian Fleischer ) have gone unanswered. >> >> Have you also tried: >> http://www.scravy.de/ >> https://github.com/scravy >> ? >> >> Btw. I think hmatrix is better for doing serious linear algebra in Haskell. >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Fri Apr 17 03:08:07 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Thu, 16 Apr 2015 23:08:07 -0400 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: if you can patch prelude error to include stack traces, i will owe you a >=1 beer each at the next two icfps. Thats all i want for christmas. :) i can't speak for how a different patch might work out, because thats not what I'd tried at the time. If you have a go, please share the results! -Carter On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan wrote: > Hi Carter! > > Interesting! This thread, right? > https://mail.haskell.org/pipermail/libraries/2014-December/024429.html > > I haven't tried this as a patch to base, but I'm certain that the core of > the proposal has no extra dependencies. Note that the proposal isn't about > stack traces in particular - that's just one application of being able to > throw exceptions with extra information. > > Even if `throwTo` isn't modified to throw exceptions with stack traces, > this functionality could be provided outside of `Control.Exception` > (though, that does seem like the right place to put it). I'm surprised > that the circularity was so problematic, though. Why isn't it sufficient > to have an hs-boot file for `GHC.Stack`, which exports `currentCallStack`? > > -Michael > > On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald < > carter.schonwald at gmail.com> wrote: > >> Hey Michael, >> I actually proposed something along these lines that got OK'd by >> libraries early this past fall, the main challenge we hit was actually >> doing the enginering to add the stack traces to exceptions! theres some >> nasty module cycles in base that happen when you try to weave things around >> so that the standard error "message here" call includes some stack trace >> info. Have you tried to do that simple starter patch to base? >> >> Chris Allen and I spent like 2 days trying to get it to work and just >> gave up because of the cycles. We (and others) would probably love some >> headway on that front. >> >> Theres also some in progress work to use the dwarf debugging info data in >> >7.10 to provide useful stack traces in the default builds for GHC afaik, >> 'cause the stack trace functionality you're pointing at currenlty only work >> on profiled builds >> >> cheers >> -Carter >> >> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan wrote: >> >>> Control.Exception currently lacks a good way to supply extra >>> information along with exceptions. For example, exceptions could be >>> thrown along with their callstack[1] or implicit stack[2], but we have >>> no generic way to include this information with exceptions. >>> >>> Proposed Solution >>> ================= >>> >>> The proposed solution is to add a list of `SomeExceptionInfo` to the >>> `SomeException` datatype. This list stores additional information >>> about the exception. These `ExceptionInfo` instances use a mechanism >>> which is pretty much identical to the dynamic way the `Exception` type >>> works: >>> >>> data SomeException = forall e . Exception e => >>> SomeExceptionWithInfo e [SomeExceptionInfo] >>> >>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>> SomeExceptionInfo a >>> >>> class Typeable a => ExceptionInfo a where >>> displayExceptionInfo :: a -> String >>> >>> addExceptionInfo >>> :: (ExceptionInfo a, Exception e) >>> => a -> e -> SomeException >>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>> >>> `ExceptionInfo` lacks the to / from functions that `Exception` has, >>> because I don't see much point in supporting a hierarchy for exception >>> info. The `Typeable` superclass constraint supplies the necessary >>> casting. >>> >>> `SomeExceptionInfo` could validly instead just use the constraint >>> `(Typeable a, Show a)`. However, I believe it's good to have a new >>> class for this so that: >>> >>> * The user can specify a custom `displayExceptionInfo` >>> implementation, for when this extra info is presented to the user. >>> This function would be invoked by the `show` implementation for >>> `SomeException`. >>> >>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>> Similarly to exceptions, I imagine that a type with a >>> `ExceptionInfo` instance won't be used for anything but acting as >>> such an annotation. Having a class for this allows you to ask GHCI >>> about all in-scope exception info types via `:info ExceptionInfo`. >>> >>> Backwards Compatibility >>> ======================= >>> >>> GHC 7.10 adds support for bidirectional pattern synonyms. This means >>> that this change could be made without breaking code: >>> >>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>> SomeException x = SomeExceptionWithInfo x [] >>> >>> Note that consumers of this do not need to enable `-XPatternSynonyms`. >>> >>> Applications >>> ============ >>> >>> Callstacks >>> ---------- >>> >>> As mentioned at the beginning, this can be used to add callstacks to >>> exceptions: >>> >>> newtype ExceptionCallStack = >>> ExceptionCallStack { unExceptionCallStack :: [String] } >>> deriving Typeable >>> >>> instance ExceptionInfo ExceptionCallStack where >>> displayExceptionInfo = unlines . unExceptionCallStack >>> >>> throwIOWithStack :: Exception e => e -> IO a >>> throwIOWithStack e = do >>> stack <- currentCallStack >>> if null stack >>> then throwIO e >>> else throwIO (addExceptionInfo (ExceptionCallStack stack) e) >>> >>> I see little downside for making something like this the default >>> implementation `throwIO`. Each rethrowing of the `SomeException` >>> would add an additional stacktrace to its annotation, much like the >>> output of `+RTS -xc`. Unlike this debug output, though, the >>> stacktraces would be associated with the exception, rather than just >>> listing locations that exceptions were thrown. This makes it >>> tractable to debug exceptions that occur in concurrent programs, or in >>> programs which frequently throw exceptions during normal functioning. >>> >>> Throwing Exceptions in Handlers >>> ------------------------------- >>> >>> Example: >>> >>> main = >>> throwIO InformativeErrorMessage `finally` >>> throwIO ObscureCleanupIssue >>> >>> While `InformativeErrorMessage` got thrown, the user doesn't see it, >>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>> issues: >>> >>> 1. If the exception is handled by the default handler and yielded to >>> the user, then the more informative error is lost. >>> >>> 2. Callers who expect to catch the "Informative error message" won't >>> run their handlers for this exception type. >>> >>> Problem 1 can now easily be resolved by adding some info to the >>> exception: >>> >>> data ExceptionCause = ExceptionCause >>> { unExceptionCause :: SomeException } >>> deriving Typeable >>> >>> instance ExceptionInfo ExceptionCause where >>> displayExceptionInfo fe = >>> "thrown while handling " ++ >>> displayException (unExceptionCause fe) >>> >>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>> catch f g = f `oldCatch` handler >>> where >>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>> throwIO (addExceptionInfo info ex') >>> where >>> info = ExceptionCause (toException ex) >>> >>> This implementation of `catch` is written in a backwards-compatible >>> way, such that the exception thrown during finalization is still the >>> one that gets rethrown. The "original" exception is recorded in the >>> added info. This is the same approach used by Python 3's >>> `__context__` attribute[3]. This was brought to my attention in a >>> post by Mike Meyer[4], in a thread about having bracket not suppress >>> the original exception[5]. >>> >>> This doesn't directly resolve issue #2, due to this backwards >>> compatibility. With the earlier example, a `catch` handler for >>> `InformativeErrorMessage` won't be invoked, because it isn't the >>> exception being rethrown. This can be resolved by having a variant of >>> catch which instead throws the original exception. This might be a >>> good default for finalization handlers like `bracket` and `finally`. >>> >>> Asynchronous Exceptions >>> ----------------------- >>> >>> Currently, the only reliable way to catch exceptions, ignoring async >>> exceptions, is to fork a new thread. This is the approach used by the >>> enclosed-exceptions[6] package. I think it's quite ugly that we need >>> to go to such lengths due to the lack of one bit of information about >>> the exception! This would resolve ghc trac #5902[7]. >>> >>> base-4.7 added the `SomeAsyncException` type, but this doesn't enforce >>> anything. Any exception can be thrown as a sync or async exception. >>> Instead, we ought to have a reliable way to know if an exception is >>> synchronous or asynchronous. Here's what this would look like: >>> >>> data IsAsync = IsAsync >>> deriving (Typeable, Show) >>> >>> instance ExceptionInfo IsAsync where >>> displayExceptionInfo IsAsync = "thrown asynchronously" >>> >>> throwTo :: Exception e => ThreadId -> e -> IO () >>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>> >>> The details of this get a bit tricky: What happens if `throwIO` is >>> used to rethrow a `SomeException` which has this `IsAsync` flag set? >>> I'm going to leave out my thoughts on this for now as the interactions >>> between unsafePerformIO and the concept of "rethrowing" async >>> exceptions. Such details are explained in a post by Edsko de Vries[8] >>> and ghc trac #2558[9]. >>> >>> Issue: fromException loses info >>> =============================== >>> >>> I can think of one main non-ideal aspect of this proposal: >>> >>> Currently, the `toException` and `fromException` methods usually form >>> a prism. In other words, when `fromException` yields a `Just`, you >>> should get the same `SomeException` when using `toException` on that >>> value. >>> >>> For example, >>> >>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex >>> >>> is equivalent to >>> >>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>> >>> However, with exception info added to just `SomeException`, and no >>> changes to existing `Exception` instances, this >>> doesn't hold. Exceptions caught as a specific exception type get >>> rethrown with less information. >>> >>> One resolution to this is be to add `[SomeExceptionInfo]` as a field >>> to existing `Exception` instances. This would require the use of >>> non-default implementations of the `toException` and `fromException` >>> instances. >>> >>> Another approach is to have variants of `catch` and `throw` which also >>> pass around the `[SomeExceptionInfo]`. >>> >>> [1] >>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>> [2] >>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>> [3] https://www.python.org/dev/peps/pep-3134/ >>> [4] >>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>> [5] >>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>> >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ezyang at mit.edu Fri Apr 17 11:21:16 2015 From: ezyang at mit.edu (Edward Z. Yang) Date: Fri, 17 Apr 2015 12:21:16 +0100 Subject: Proposal: liftData for Template Haskell Message-ID: <1429269330-sup-7487@sabre> I propose adding the following function to Language.Haskell.TH: -- | 'liftData' is a variant of 'lift' in the 'Lift' type class which -- works for any type with a 'Data' instance. liftData :: Data a => a -> Q Exp liftData = dataToExpQ (const Nothing) I don't really know which submodule this should come from; since it uses 'dataToExpQ', you might put it in Language.Haskell.TH.Quote but arguably 'dataToExpQ' doesn't belong in this module either, and it only lives there because it is a useful function for defining quasiquoters and it was described in the quasiquoting paper. I might propose getting rid of the 'Lift' class entirely, but you might prefer that class since it doesn't go through SYB (and have the attendant slowdown). This mode of use of 'dataToExpQ' deserves more attention. Discussion period: 1 month Cheers, Edward From eir at cis.upenn.edu Fri Apr 17 20:26:24 2015 From: eir at cis.upenn.edu (Richard Eisenberg) Date: Fri, 17 Apr 2015 16:26:24 -0400 Subject: Proposal: liftData for Template Haskell In-Reply-To: <1429269330-sup-7487@sabre> References: <1429269330-sup-7487@sabre> Message-ID: <7D2F6B1C-AB8A-4933-AE2A-C00F23DC419F@cis.upenn.edu> +1 But don't remove Lift. I need it to be able to lift types that have unlifted(*) data. (*): Of course, the "lift" root of the word unlifted is entirely unrelated to the use of "lift" earlier in the same sentence. Urgh. Good idea! Richard On Apr 17, 2015, at 7:21 AM, "Edward Z. Yang" wrote: > I propose adding the following function to Language.Haskell.TH: > > -- | 'liftData' is a variant of 'lift' in the 'Lift' type class which > -- works for any type with a 'Data' instance. > liftData :: Data a => a -> Q Exp > liftData = dataToExpQ (const Nothing) > > I don't really know which submodule this should come from; > since it uses 'dataToExpQ', you might put it in Language.Haskell.TH.Quote > but arguably 'dataToExpQ' doesn't belong in this module either, > and it only lives there because it is a useful function for defining > quasiquoters and it was described in the quasiquoting paper. > > I might propose getting rid of the 'Lift' class entirely, but you > might prefer that class since it doesn't go through SYB (and have > the attendant slowdown). > > This mode of use of 'dataToExpQ' deserves more attention. > > Discussion period: 1 month > > Cheers, > Edward > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries From mgsloan at gmail.com Sat Apr 18 19:50:39 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Sat, 18 Apr 2015 12:50:39 -0700 Subject: Proposal: liftData for Template Haskell In-Reply-To: <1429269330-sup-7487@sabre> References: <1429269330-sup-7487@sabre> Message-ID: +1 to liftData Removing 'Lift' altogether definitely isn't the way to go, though. As Richard points out, we want to be able to lift more than just ADTs. Also ADTs which hide their implementation can have either opaque Data instances, no Data instance, or Data instances which involve using functions for constructors. An example of the latter is Data.Map.Map's Data instance, which uses 'fromList' as a constructor. This results in $(dataToExpQ (\_ -> Nothing) (fromList [(1,2)])) causing the compiletime error "Illegal data constructor name: ?fromList?". I think 'dataToExpQ' and related functions should be modified to handle this case. It should be rather easy - if the constructor Name is lowercase, generate a 'VarE' instead of a 'ConE'. I suppose this is a separate proposal, but it came up when thinking about this proposal. -Michael On Fri, Apr 17, 2015 at 4:21 AM, Edward Z. Yang wrote: > I propose adding the following function to Language.Haskell.TH: > > -- | 'liftData' is a variant of 'lift' in the 'Lift' type class which > -- works for any type with a 'Data' instance. > liftData :: Data a => a -> Q Exp > liftData = dataToExpQ (const Nothing) > > I don't really know which submodule this should come from; > since it uses 'dataToExpQ', you might put it in Language.Haskell.TH.Quote > but arguably 'dataToExpQ' doesn't belong in this module either, > and it only lives there because it is a useful function for defining > quasiquoters and it was described in the quasiquoting paper. > > I might propose getting rid of the 'Lift' class entirely, but you > might prefer that class since it doesn't go through SYB (and have > the attendant slowdown). > > This mode of use of 'dataToExpQ' deserves more attention. > > Discussion period: 1 month > > Cheers, > Edward > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From simonpj at microsoft.com Mon Apr 20 08:12:07 2015 From: simonpj at microsoft.com (Simon Peyton Jones) Date: Mon, 20 Apr 2015 08:12:07 +0000 Subject: Cabal and simultaneous installations of the same package In-Reply-To: <68326f3ebbd943768effe6b0f2ff522c@DB4PR30MB030.064d.mgd.msft.net> References: <68326f3ebbd943768effe6b0f2ff522c@DB4PR30MB030.064d.mgd.msft.net> Message-ID: Friends We started this thread (below) a month ago, but it has once more run out of steam. The last contribution was from Vishal Agrawal I am already planning to do a GSoC project based on it with a slightly larger aim. You can find my work in progress proposal at https://gist.github.com/fugyk/37510958b52589737274. Also I have written a patch to make cabal non-destructive at https://github.com/fugyk/cabal/commit/45ec5edbaada1fd063c67d6109e69efa0e732e6a. Can you review the proposal and give me suggestions. I don't feel qualified to drive this process, but I do think it's important to complete it. (I might be wrong about this too... please say so if so.) Nor do I understand why it's difficult to tie up the bow; the underlying infrastructure work is done. Duncan especially: how can we make progress? Do you think it's important to make progress, or are other things in cabal-land more important? My reason for thinking that it's important is that it appears to be the root cause of many people's difficulties with Haskell and Cabal. It might not be a panacea for all ills; but it might be a cheap remedy for a significant proportion of ills. And that would be a Good Thing. Thanks Simon | -----Original Message----- | From: ghc-devs [mailto:ghc-devs-bounces at haskell.org] On Behalf Of Simon | Peyton Jones | Sent: 23 March 2015 08:46 | To: cabal-devel at haskell.org | Cc: haskell-platform at projects.haskell.org; haskell- | infrastructure at community.galois.com; Haskell Libraries; ghc- | devs at haskell.org | Subject: Cabal and simultaneous installations of the same package | | Dear Cabal developers | | You'll probably have seen the thread about the Haskell Platform. | | Among other things, this point arose: | | | Another thing we should fix is the (now false) impression that HP | | gets in the way of installing other packages and versions due to | cabal hell. | | People mean different things by "cabal hell", but the inability to | simultaneously install multiple versions of the same package, | compiled against different dependencies is certainly one of them, | and I think it is the one that Yitzchak is referring to here. | | But some time now GHC has allowed multiple versions of the same package | (compiled against different dependencies) to be installed | simultaneously. So all we need to do is to fix Cabal to allow it too, | and thereby kill of a huge class of cabal-hell problems at one blow. | | But time has passed and it hasn't happened. Is this because I'm | misunderstanding? Or because it is harder than I think? Or because | there are much bigger problems? Or because there is insufficient | effort available? Or what? | | Unless I'm way off beam, this "multiple installations of the same | package" thing has been a huge pain forever, and the solution is within | our grasp. What's stopping us grasping it? | | Simon | | _______________________________________________ | ghc-devs mailing list | ghc-devs at haskell.org | http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Tue Apr 21 03:20:15 2015 From: david.feuer at gmail.com (David Feuer) Date: Mon, 20 Apr 2015 23:20:15 -0400 Subject: Data.Tree traversals Message-ID: Data.Tree makes Tree into a Traversable in only one way: depth-first. It seems to me that we should have a newtype to traverse in breadth-first order. David Feuer -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Tue Apr 21 04:01:57 2015 From: michael at snoyman.com (Michael Snoyman) Date: Tue, 21 Apr 2015 04:01:57 +0000 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Sorry to confuse this thread with a second Michael. I spoke with Michael Sloan about this proposal before he made it. I'm usually very hesitant to introduce breaking changes to core APIs, but in this case (1) there's a very good use case that's currently excluded by the API, and (2) Michael Sloan figured out some great ways to minimize the breakage. You could even argue that this proposal has *no* API breakage. I'm +1 on including it. I'm also hopeful that we can address the `error = errorWithStackTrace`, but that would really be a step 2 after the changes to SomeException are made. On Wed, Apr 15, 2015 at 5:56 AM Carter Schonwald wrote: > Hey Michael, > I actually proposed something along these lines that got OK'd by libraries > early this past fall, the main challenge we hit was actually doing the > enginering to add the stack traces to exceptions! theres some nasty module > cycles in base that happen when you try to weave things around so that the > standard error "message here" call includes some stack trace info. Have you > tried to do that simple starter patch to base? > > Chris Allen and I spent like 2 days trying to get it to work and just gave > up because of the cycles. We (and others) would probably love some headway > on that front. > > Theres also some in progress work to use the dwarf debugging info data in > >7.10 to provide useful stack traces in the default builds for GHC afaik, > 'cause the stack trace functionality you're pointing at currenlty only work > on profiled builds > > cheers > -Carter > > On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan wrote: > >> Control.Exception currently lacks a good way to supply extra >> information along with exceptions. For example, exceptions could be >> thrown along with their callstack[1] or implicit stack[2], but we have >> no generic way to include this information with exceptions. >> >> Proposed Solution >> ================= >> >> The proposed solution is to add a list of `SomeExceptionInfo` to the >> `SomeException` datatype. This list stores additional information >> about the exception. These `ExceptionInfo` instances use a mechanism >> which is pretty much identical to the dynamic way the `Exception` type >> works: >> >> data SomeException = forall e . Exception e => >> SomeExceptionWithInfo e [SomeExceptionInfo] >> >> data SomeExceptionInfo = forall a . ExceptionInfo a => >> SomeExceptionInfo a >> >> class Typeable a => ExceptionInfo a where >> displayExceptionInfo :: a -> String >> >> addExceptionInfo >> :: (ExceptionInfo a, Exception e) >> => a -> e -> SomeException >> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >> >> `ExceptionInfo` lacks the to / from functions that `Exception` has, >> because I don't see much point in supporting a hierarchy for exception >> info. The `Typeable` superclass constraint supplies the necessary >> casting. >> >> `SomeExceptionInfo` could validly instead just use the constraint >> `(Typeable a, Show a)`. However, I believe it's good to have a new >> class for this so that: >> >> * The user can specify a custom `displayExceptionInfo` >> implementation, for when this extra info is presented to the user. >> This function would be invoked by the `show` implementation for >> `SomeException`. >> >> * Types need to opt-in to be usable with `SomeExceptionInfo`. >> Similarly to exceptions, I imagine that a type with a >> `ExceptionInfo` instance won't be used for anything but acting as >> such an annotation. Having a class for this allows you to ask GHCI >> about all in-scope exception info types via `:info ExceptionInfo`. >> >> Backwards Compatibility >> ======================= >> >> GHC 7.10 adds support for bidirectional pattern synonyms. This means >> that this change could be made without breaking code: >> >> pattern SomeException x <- SomeExceptionWithInfo x _ where >> SomeException x = SomeExceptionWithInfo x [] >> >> Note that consumers of this do not need to enable `-XPatternSynonyms`. >> >> Applications >> ============ >> >> Callstacks >> ---------- >> >> As mentioned at the beginning, this can be used to add callstacks to >> exceptions: >> >> newtype ExceptionCallStack = >> ExceptionCallStack { unExceptionCallStack :: [String] } >> deriving Typeable >> >> instance ExceptionInfo ExceptionCallStack where >> displayExceptionInfo = unlines . unExceptionCallStack >> >> throwIOWithStack :: Exception e => e -> IO a >> throwIOWithStack e = do >> stack <- currentCallStack >> if null stack >> then throwIO e >> else throwIO (addExceptionInfo (ExceptionCallStack stack) e) >> >> I see little downside for making something like this the default >> implementation `throwIO`. Each rethrowing of the `SomeException` >> would add an additional stacktrace to its annotation, much like the >> output of `+RTS -xc`. Unlike this debug output, though, the >> stacktraces would be associated with the exception, rather than just >> listing locations that exceptions were thrown. This makes it >> tractable to debug exceptions that occur in concurrent programs, or in >> programs which frequently throw exceptions during normal functioning. >> >> Throwing Exceptions in Handlers >> ------------------------------- >> >> Example: >> >> main = >> throwIO InformativeErrorMessage `finally` >> throwIO ObscureCleanupIssue >> >> While `InformativeErrorMessage` got thrown, the user doesn't see it, >> since `ObscureCleanupIssue` is thrown instead. This causes a few >> issues: >> >> 1. If the exception is handled by the default handler and yielded to >> the user, then the more informative error is lost. >> >> 2. Callers who expect to catch the "Informative error message" won't >> run their handlers for this exception type. >> >> Problem 1 can now easily be resolved by adding some info to the >> exception: >> >> data ExceptionCause = ExceptionCause >> { unExceptionCause :: SomeException } >> deriving Typeable >> >> instance ExceptionInfo ExceptionCause where >> displayExceptionInfo fe = >> "thrown while handling " ++ >> displayException (unExceptionCause fe) >> >> catch :: Exception e => IO a -> (e -> IO a) -> IO a >> catch f g = f `oldCatch` handler >> where >> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >> throwIO (addExceptionInfo info ex') >> where >> info = ExceptionCause (toException ex) >> >> This implementation of `catch` is written in a backwards-compatible >> way, such that the exception thrown during finalization is still the >> one that gets rethrown. The "original" exception is recorded in the >> added info. This is the same approach used by Python 3's >> `__context__` attribute[3]. This was brought to my attention in a >> post by Mike Meyer[4], in a thread about having bracket not suppress >> the original exception[5]. >> >> This doesn't directly resolve issue #2, due to this backwards >> compatibility. With the earlier example, a `catch` handler for >> `InformativeErrorMessage` won't be invoked, because it isn't the >> exception being rethrown. This can be resolved by having a variant of >> catch which instead throws the original exception. This might be a >> good default for finalization handlers like `bracket` and `finally`. >> >> Asynchronous Exceptions >> ----------------------- >> >> Currently, the only reliable way to catch exceptions, ignoring async >> exceptions, is to fork a new thread. This is the approach used by the >> enclosed-exceptions[6] package. I think it's quite ugly that we need >> to go to such lengths due to the lack of one bit of information about >> the exception! This would resolve ghc trac #5902[7]. >> >> base-4.7 added the `SomeAsyncException` type, but this doesn't enforce >> anything. Any exception can be thrown as a sync or async exception. >> Instead, we ought to have a reliable way to know if an exception is >> synchronous or asynchronous. Here's what this would look like: >> >> data IsAsync = IsAsync >> deriving (Typeable, Show) >> >> instance ExceptionInfo IsAsync where >> displayExceptionInfo IsAsync = "thrown asynchronously" >> >> throwTo :: Exception e => ThreadId -> e -> IO () >> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >> >> The details of this get a bit tricky: What happens if `throwIO` is >> used to rethrow a `SomeException` which has this `IsAsync` flag set? >> I'm going to leave out my thoughts on this for now as the interactions >> between unsafePerformIO and the concept of "rethrowing" async >> exceptions. Such details are explained in a post by Edsko de Vries[8] >> and ghc trac #2558[9]. >> >> Issue: fromException loses info >> =============================== >> >> I can think of one main non-ideal aspect of this proposal: >> >> Currently, the `toException` and `fromException` methods usually form >> a prism. In other words, when `fromException` yields a `Just`, you >> should get the same `SomeException` when using `toException` on that >> value. >> >> For example, >> >> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex >> >> is equivalent to >> >> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >> >> However, with exception info added to just `SomeException`, and no >> changes to existing `Exception` instances, this >> doesn't hold. Exceptions caught as a specific exception type get >> rethrown with less information. >> >> One resolution to this is be to add `[SomeExceptionInfo]` as a field >> to existing `Exception` instances. This would require the use of >> non-default implementations of the `toException` and `fromException` >> instances. >> >> Another approach is to have variants of `catch` and `throw` which also >> pass around the `[SomeExceptionInfo]`. >> >> [1] >> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >> [2] >> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >> [3] https://www.python.org/dev/peps/pep-3134/ >> [4] https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >> [5] https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >> [6] https://hackage.haskell.org/package/enclosed-exceptions >> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >> [8] http://www.edsko.net/2013/06/11/throwTo/ >> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danburton.email at gmail.com Tue Apr 21 04:08:00 2015 From: danburton.email at gmail.com (Dan Burton) Date: Mon, 20 Apr 2015 21:08:00 -0700 Subject: Data.Tree traversals In-Reply-To: References: Message-ID: +1 I don't see why not. Pre-order and post-order are also pretty textbook traversals. I don't imagine they'll be used very heavily, but they're certainly good for learning purposes. Perhaps instead of newtypes for each of these, we can just provide the corresponding "traverse" function. These types unsurprisingly correspond to lens's Traversal (Tree a) (Tree b) a b. depthFirst :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) depthFirst = ... preOrder :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) preOrder = ... postOrder :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) postOrder = ... inOrder :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) inOrder = traverse -- Dan Burton On Mon, Apr 20, 2015 at 8:20 PM, David Feuer wrote: > Data.Tree makes Tree into a Traversable in only one way: depth-first. It > seems to me that we should have a newtype to traverse in breadth-first > order. > > David Feuer > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Tue Apr 21 04:50:31 2015 From: david.feuer at gmail.com (David Feuer) Date: Tue, 21 Apr 2015 00:50:31 -0400 Subject: Data.Tree traversals In-Reply-To: References: Message-ID: Er... I may have mixed up preorder and depth-first -- I tend to do that. The point is, whatever it doesn't do, it should do. On Tue, Apr 21, 2015 at 12:08 AM, Dan Burton wrote: > +1 I don't see why not. Pre-order and post-order are also pretty textbook > traversals. I don't imagine they'll be used very heavily, but they're > certainly good for learning purposes. > > Perhaps instead of newtypes for each of these, we can just provide the > corresponding "traverse" function. These types unsurprisingly correspond to > lens's Traversal (Tree a) (Tree b) a b. > > depthFirst :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) > depthFirst = ... > > preOrder :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) > preOrder = ... > > postOrder :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) > postOrder = ... > > inOrder :: Applicative f => (a -> f b) -> Tree a -> f (Tree b) > inOrder = traverse > > -- Dan Burton > > On Mon, Apr 20, 2015 at 8:20 PM, David Feuer > wrote: > >> Data.Tree makes Tree into a Traversable in only one way: depth-first. It >> seems to me that we should have a newtype to traverse in breadth-first >> order. >> >> David Feuer >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jwlato at gmail.com Tue Apr 21 05:27:34 2015 From: jwlato at gmail.com (John Lato) Date: Tue, 21 Apr 2015 05:27:34 +0000 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: I don't have a strong opinion towards this proposal. It definitely seems useful, but I think most of the uses would be either somewhat niche in practice, or better addressed by other mechanisms (the call stack stuff). However I am opposed to adding IsAsync, because I do not think it is useful. In every case I know where a user wants to differentiate async exceptions, what they actually want is to differentiate RTS control exceptions from everything else. I think the proposal would easily accommodate that, and you could have IsAsync too if there is a use case for it. On Thu, Apr 16, 2015, 8:08 PM Carter Schonwald wrote: > if you can patch prelude error to include stack traces, i will owe you a > >=1 beer each at the next two icfps. Thats all i want for christmas. :) > > i can't speak for how a different patch might work out, because thats not > what I'd tried at the time. If you have a go, please share the results! > -Carter > > On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan wrote: > >> Hi Carter! >> >> Interesting! This thread, right? >> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >> >> I haven't tried this as a patch to base, but I'm certain that the core of >> the proposal has no extra dependencies. Note that the proposal isn't about >> stack traces in particular - that's just one application of being able to >> throw exceptions with extra information. >> >> Even if `throwTo` isn't modified to throw exceptions with stack traces, >> this functionality could be provided outside of `Control.Exception` >> (though, that does seem like the right place to put it). I'm surprised >> that the circularity was so problematic, though. Why isn't it sufficient >> to have an hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >> >> -Michael >> >> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> Hey Michael, >>> I actually proposed something along these lines that got OK'd by >>> libraries early this past fall, the main challenge we hit was actually >>> doing the enginering to add the stack traces to exceptions! theres some >>> nasty module cycles in base that happen when you try to weave things around >>> so that the standard error "message here" call includes some stack trace >>> info. Have you tried to do that simple starter patch to base? >>> >>> Chris Allen and I spent like 2 days trying to get it to work and just >>> gave up because of the cycles. We (and others) would probably love some >>> headway on that front. >>> >>> Theres also some in progress work to use the dwarf debugging info data >>> in >7.10 to provide useful stack traces in the default builds for GHC >>> afaik, 'cause the stack trace functionality you're pointing at currenlty >>> only work on profiled builds >>> >>> cheers >>> -Carter >>> >>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >>> wrote: >>> >>>> Control.Exception currently lacks a good way to supply extra >>>> information along with exceptions. For example, exceptions could be >>>> thrown along with their callstack[1] or implicit stack[2], but we have >>>> no generic way to include this information with exceptions. >>>> >>>> Proposed Solution >>>> ================= >>>> >>>> The proposed solution is to add a list of `SomeExceptionInfo` to the >>>> `SomeException` datatype. This list stores additional information >>>> about the exception. These `ExceptionInfo` instances use a mechanism >>>> which is pretty much identical to the dynamic way the `Exception` type >>>> works: >>>> >>>> data SomeException = forall e . Exception e => >>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>> >>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>> SomeExceptionInfo a >>>> >>>> class Typeable a => ExceptionInfo a where >>>> displayExceptionInfo :: a -> String >>>> >>>> addExceptionInfo >>>> :: (ExceptionInfo a, Exception e) >>>> => a -> e -> SomeException >>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>> >>>> `ExceptionInfo` lacks the to / from functions that `Exception` has, >>>> because I don't see much point in supporting a hierarchy for exception >>>> info. The `Typeable` superclass constraint supplies the necessary >>>> casting. >>>> >>>> `SomeExceptionInfo` could validly instead just use the constraint >>>> `(Typeable a, Show a)`. However, I believe it's good to have a new >>>> class for this so that: >>>> >>>> * The user can specify a custom `displayExceptionInfo` >>>> implementation, for when this extra info is presented to the user. >>>> This function would be invoked by the `show` implementation for >>>> `SomeException`. >>>> >>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>> Similarly to exceptions, I imagine that a type with a >>>> `ExceptionInfo` instance won't be used for anything but acting as >>>> such an annotation. Having a class for this allows you to ask GHCI >>>> about all in-scope exception info types via `:info ExceptionInfo`. >>>> >>>> Backwards Compatibility >>>> ======================= >>>> >>>> GHC 7.10 adds support for bidirectional pattern synonyms. This means >>>> that this change could be made without breaking code: >>>> >>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>> SomeException x = SomeExceptionWithInfo x [] >>>> >>>> Note that consumers of this do not need to enable `-XPatternSynonyms`. >>>> >>>> Applications >>>> ============ >>>> >>>> Callstacks >>>> ---------- >>>> >>>> As mentioned at the beginning, this can be used to add callstacks to >>>> exceptions: >>>> >>>> newtype ExceptionCallStack = >>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>> deriving Typeable >>>> >>>> instance ExceptionInfo ExceptionCallStack where >>>> displayExceptionInfo = unlines . unExceptionCallStack >>>> >>>> throwIOWithStack :: Exception e => e -> IO a >>>> throwIOWithStack e = do >>>> stack <- currentCallStack >>>> if null stack >>>> then throwIO e >>>> else throwIO (addExceptionInfo (ExceptionCallStack stack) e) >>>> >>>> I see little downside for making something like this the default >>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>>> would add an additional stacktrace to its annotation, much like the >>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>> stacktraces would be associated with the exception, rather than just >>>> listing locations that exceptions were thrown. This makes it >>>> tractable to debug exceptions that occur in concurrent programs, or in >>>> programs which frequently throw exceptions during normal functioning. >>>> >>>> Throwing Exceptions in Handlers >>>> ------------------------------- >>>> >>>> Example: >>>> >>>> main = >>>> throwIO InformativeErrorMessage `finally` >>>> throwIO ObscureCleanupIssue >>>> >>>> While `InformativeErrorMessage` got thrown, the user doesn't see it, >>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>>> issues: >>>> >>>> 1. If the exception is handled by the default handler and yielded to >>>> the user, then the more informative error is lost. >>>> >>>> 2. Callers who expect to catch the "Informative error message" won't >>>> run their handlers for this exception type. >>>> >>>> Problem 1 can now easily be resolved by adding some info to the >>>> exception: >>>> >>>> data ExceptionCause = ExceptionCause >>>> { unExceptionCause :: SomeException } >>>> deriving Typeable >>>> >>>> instance ExceptionInfo ExceptionCause where >>>> displayExceptionInfo fe = >>>> "thrown while handling " ++ >>>> displayException (unExceptionCause fe) >>>> >>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>> catch f g = f `oldCatch` handler >>>> where >>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>> throwIO (addExceptionInfo info ex') >>>> where >>>> info = ExceptionCause (toException ex) >>>> >>>> This implementation of `catch` is written in a backwards-compatible >>>> way, such that the exception thrown during finalization is still the >>>> one that gets rethrown. The "original" exception is recorded in the >>>> added info. This is the same approach used by Python 3's >>>> `__context__` attribute[3]. This was brought to my attention in a >>>> post by Mike Meyer[4], in a thread about having bracket not suppress >>>> the original exception[5]. >>>> >>>> This doesn't directly resolve issue #2, due to this backwards >>>> compatibility. With the earlier example, a `catch` handler for >>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>> exception being rethrown. This can be resolved by having a variant of >>>> catch which instead throws the original exception. This might be a >>>> good default for finalization handlers like `bracket` and `finally`. >>>> >>>> Asynchronous Exceptions >>>> ----------------------- >>>> >>>> Currently, the only reliable way to catch exceptions, ignoring async >>>> exceptions, is to fork a new thread. This is the approach used by the >>>> enclosed-exceptions[6] package. I think it's quite ugly that we need >>>> to go to such lengths due to the lack of one bit of information about >>>> the exception! This would resolve ghc trac #5902[7]. >>>> >>>> base-4.7 added the `SomeAsyncException` type, but this doesn't enforce >>>> anything. Any exception can be thrown as a sync or async exception. >>>> Instead, we ought to have a reliable way to know if an exception is >>>> synchronous or asynchronous. Here's what this would look like: >>>> >>>> data IsAsync = IsAsync >>>> deriving (Typeable, Show) >>>> >>>> instance ExceptionInfo IsAsync where >>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>> >>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>> >>>> The details of this get a bit tricky: What happens if `throwIO` is >>>> used to rethrow a `SomeException` which has this `IsAsync` flag set? >>>> I'm going to leave out my thoughts on this for now as the interactions >>>> between unsafePerformIO and the concept of "rethrowing" async >>>> exceptions. Such details are explained in a post by Edsko de Vries[8] >>>> and ghc trac #2558[9]. >>>> >>>> Issue: fromException loses info >>>> =============================== >>>> >>>> I can think of one main non-ideal aspect of this proposal: >>>> >>>> Currently, the `toException` and `fromException` methods usually form >>>> a prism. In other words, when `fromException` yields a `Just`, you >>>> should get the same `SomeException` when using `toException` on that >>>> value. >>>> >>>> For example, >>>> >>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex >>>> >>>> is equivalent to >>>> >>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>> >>>> However, with exception info added to just `SomeException`, and no >>>> changes to existing `Exception` instances, this >>>> doesn't hold. Exceptions caught as a specific exception type get >>>> rethrown with less information. >>>> >>>> One resolution to this is be to add `[SomeExceptionInfo]` as a field >>>> to existing `Exception` instances. This would require the use of >>>> non-default implementations of the `toException` and `fromException` >>>> instances. >>>> >>>> Another approach is to have variants of `catch` and `throw` which also >>>> pass around the `[SomeExceptionInfo]`. >>>> >>>> [1] >>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>> [2] >>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>> [4] >>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>> [5] >>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>> >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >>> >> > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Tue Apr 21 05:40:38 2015 From: michael at snoyman.com (Michael Snoyman) Date: Tue, 21 Apr 2015 05:40:38 +0000 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: The typical case for wanting to distinguish sync from async exceptions that I'm aware of is using timeout, e.g.: timeout (try someAction :: IO (Either SomeException SomeActionResult) A more concrete example is available in the second code snippet at [1]. [1] https://www.fpcomplete.com/user/snoyberg/general-haskell/exceptions/catching-all-exceptions On Tue, Apr 21, 2015 at 8:27 AM John Lato wrote: > I don't have a strong opinion towards this proposal. It definitely seems > useful, but I think most of the uses would be either somewhat niche in > practice, or better addressed by other mechanisms (the call stack stuff). > > However I am opposed to adding IsAsync, because I do not think it is > useful. In every case I know where a user wants to differentiate async > exceptions, what they actually want is to differentiate RTS control > exceptions from everything else. I think the proposal would easily > accommodate that, and you could have IsAsync too if there is a use case for > it. > > On Thu, Apr 16, 2015, 8:08 PM Carter Schonwald > wrote: > >> if you can patch prelude error to include stack traces, i will owe you a >> >=1 beer each at the next two icfps. Thats all i want for christmas. :) >> >> i can't speak for how a different patch might work out, because thats not >> what I'd tried at the time. If you have a go, please share the results! >> -Carter >> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >> wrote: >> >>> Hi Carter! >>> >>> Interesting! This thread, right? >>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>> >>> I haven't tried this as a patch to base, but I'm certain that the core >>> of the proposal has no extra dependencies. Note that the proposal isn't >>> about stack traces in particular - that's just one application of being >>> able to throw exceptions with extra information. >>> >>> Even if `throwTo` isn't modified to throw exceptions with stack traces, >>> this functionality could be provided outside of `Control.Exception` >>> (though, that does seem like the right place to put it). I'm surprised >>> that the circularity was so problematic, though. Why isn't it sufficient >>> to have an hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>> >>> -Michael >>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald < >>> carter.schonwald at gmail.com> wrote: >>> >>>> Hey Michael, >>>> I actually proposed something along these lines that got OK'd by >>>> libraries early this past fall, the main challenge we hit was actually >>>> doing the enginering to add the stack traces to exceptions! theres some >>>> nasty module cycles in base that happen when you try to weave things around >>>> so that the standard error "message here" call includes some stack trace >>>> info. Have you tried to do that simple starter patch to base? >>>> >>>> Chris Allen and I spent like 2 days trying to get it to work and just >>>> gave up because of the cycles. We (and others) would probably love some >>>> headway on that front. >>>> >>>> Theres also some in progress work to use the dwarf debugging info data >>>> in >7.10 to provide useful stack traces in the default builds for GHC >>>> afaik, 'cause the stack trace functionality you're pointing at currenlty >>>> only work on profiled builds >>>> >>>> cheers >>>> -Carter >>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >>>> wrote: >>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>> information along with exceptions. For example, exceptions could be >>>>> thrown along with their callstack[1] or implicit stack[2], but we have >>>>> no generic way to include this information with exceptions. >>>>> >>>>> Proposed Solution >>>>> ================= >>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` to the >>>>> `SomeException` datatype. This list stores additional information >>>>> about the exception. These `ExceptionInfo` instances use a mechanism >>>>> which is pretty much identical to the dynamic way the `Exception` type >>>>> works: >>>>> >>>>> data SomeException = forall e . Exception e => >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>> SomeExceptionInfo a >>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>> displayExceptionInfo :: a -> String >>>>> >>>>> addExceptionInfo >>>>> :: (ExceptionInfo a, Exception e) >>>>> => a -> e -> SomeException >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` has, >>>>> because I don't see much point in supporting a hierarchy for exception >>>>> info. The `Typeable` superclass constraint supplies the necessary >>>>> casting. >>>>> >>>>> `SomeExceptionInfo` could validly instead just use the constraint >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a new >>>>> class for this so that: >>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>> implementation, for when this extra info is presented to the user. >>>>> This function would be invoked by the `show` implementation for >>>>> `SomeException`. >>>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>> Similarly to exceptions, I imagine that a type with a >>>>> `ExceptionInfo` instance won't be used for anything but acting as >>>>> such an annotation. Having a class for this allows you to ask GHCI >>>>> about all in-scope exception info types via `:info ExceptionInfo`. >>>>> >>>>> Backwards Compatibility >>>>> ======================= >>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This means >>>>> that this change could be made without breaking code: >>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>> >>>>> Note that consumers of this do not need to enable `-XPatternSynonyms`. >>>>> >>>>> Applications >>>>> ============ >>>>> >>>>> Callstacks >>>>> ---------- >>>>> >>>>> As mentioned at the beginning, this can be used to add callstacks to >>>>> exceptions: >>>>> >>>>> newtype ExceptionCallStack = >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>> deriving Typeable >>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>> throwIOWithStack e = do >>>>> stack <- currentCallStack >>>>> if null stack >>>>> then throwIO e >>>>> else throwIO (addExceptionInfo (ExceptionCallStack stack) >>>>> e) >>>>> >>>>> I see little downside for making something like this the default >>>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>>>> would add an additional stacktrace to its annotation, much like the >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>> stacktraces would be associated with the exception, rather than just >>>>> listing locations that exceptions were thrown. This makes it >>>>> tractable to debug exceptions that occur in concurrent programs, or in >>>>> programs which frequently throw exceptions during normal functioning. >>>>> >>>>> Throwing Exceptions in Handlers >>>>> ------------------------------- >>>>> >>>>> Example: >>>>> >>>>> main = >>>>> throwIO InformativeErrorMessage `finally` >>>>> throwIO ObscureCleanupIssue >>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't see it, >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>>>> issues: >>>>> >>>>> 1. If the exception is handled by the default handler and yielded to >>>>> the user, then the more informative error is lost. >>>>> >>>>> 2. Callers who expect to catch the "Informative error message" won't >>>>> run their handlers for this exception type. >>>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>>> exception: >>>>> >>>>> data ExceptionCause = ExceptionCause >>>>> { unExceptionCause :: SomeException } >>>>> deriving Typeable >>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>> displayExceptionInfo fe = >>>>> "thrown while handling " ++ >>>>> displayException (unExceptionCause fe) >>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>> catch f g = f `oldCatch` handler >>>>> where >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>> throwIO (addExceptionInfo info ex') >>>>> where >>>>> info = ExceptionCause (toException ex) >>>>> >>>>> This implementation of `catch` is written in a backwards-compatible >>>>> way, such that the exception thrown during finalization is still the >>>>> one that gets rethrown. The "original" exception is recorded in the >>>>> added info. This is the same approach used by Python 3's >>>>> `__context__` attribute[3]. This was brought to my attention in a >>>>> post by Mike Meyer[4], in a thread about having bracket not suppress >>>>> the original exception[5]. >>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>> compatibility. With the earlier example, a `catch` handler for >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>>> exception being rethrown. This can be resolved by having a variant of >>>>> catch which instead throws the original exception. This might be a >>>>> good default for finalization handlers like `bracket` and `finally`. >>>>> >>>>> Asynchronous Exceptions >>>>> ----------------------- >>>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring async >>>>> exceptions, is to fork a new thread. This is the approach used by the >>>>> enclosed-exceptions[6] package. I think it's quite ugly that we need >>>>> to go to such lengths due to the lack of one bit of information about >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't enforce >>>>> anything. Any exception can be thrown as a sync or async exception. >>>>> Instead, we ought to have a reliable way to know if an exception is >>>>> synchronous or asynchronous. Here's what this would look like: >>>>> >>>>> data IsAsync = IsAsync >>>>> deriving (Typeable, Show) >>>>> >>>>> instance ExceptionInfo IsAsync where >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>> >>>>> The details of this get a bit tricky: What happens if `throwIO` is >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag set? >>>>> I'm going to leave out my thoughts on this for now as the interactions >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>> exceptions. Such details are explained in a post by Edsko de Vries[8] >>>>> and ghc trac #2558[9]. >>>>> >>>>> Issue: fromException loses info >>>>> =============================== >>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>> >>>>> Currently, the `toException` and `fromException` methods usually form >>>>> a prism. In other words, when `fromException` yields a `Just`, you >>>>> should get the same `SomeException` when using `toException` on that >>>>> value. >>>>> >>>>> For example, >>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex >>>>> >>>>> is equivalent to >>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>> >>>>> However, with exception info added to just `SomeException`, and no >>>>> changes to existing `Exception` instances, this >>>>> doesn't hold. Exceptions caught as a specific exception type get >>>>> rethrown with less information. >>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a field >>>>> to existing `Exception` instances. This would require the use of >>>>> non-default implementations of the `toException` and `fromException` >>>>> instances. >>>>> >>>>> Another approach is to have variants of `catch` and `throw` which also >>>>> pass around the `[SomeExceptionInfo]`. >>>>> >>>>> [1] >>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>> [2] >>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>> [4] >>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>> [5] >>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>> >>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>>> >>> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jwlato at gmail.com Tue Apr 21 05:44:53 2015 From: jwlato at gmail.com (John Lato) Date: Tue, 21 Apr 2015 05:44:53 +0000 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: That seems reasonable. Objection withdrawn, which makes me neutral overall. On Mon, Apr 20, 2015, 10:40 PM Michael Snoyman wrote: > The typical case for wanting to distinguish sync from async exceptions > that I'm aware of is using timeout, e.g.: > > timeout (try someAction :: IO (Either SomeException SomeActionResult) > > A more concrete example is available in the second code snippet at [1]. > > [1] > https://www.fpcomplete.com/user/snoyberg/general-haskell/exceptions/catching-all-exceptions > > On Tue, Apr 21, 2015 at 8:27 AM John Lato wrote: > >> I don't have a strong opinion towards this proposal. It definitely seems >> useful, but I think most of the uses would be either somewhat niche in >> practice, or better addressed by other mechanisms (the call stack stuff). >> >> However I am opposed to adding IsAsync, because I do not think it is >> useful. In every case I know where a user wants to differentiate async >> exceptions, what they actually want is to differentiate RTS control >> exceptions from everything else. I think the proposal would easily >> accommodate that, and you could have IsAsync too if there is a use case for >> it. >> >> On Thu, Apr 16, 2015, 8:08 PM Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> if you can patch prelude error to include stack traces, i will owe you a >>> >=1 beer each at the next two icfps. Thats all i want for christmas. :) >>> >>> i can't speak for how a different patch might work out, because thats >>> not what I'd tried at the time. If you have a go, please share the results! >>> -Carter >>> >>> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >>> wrote: >>> >>>> Hi Carter! >>>> >>>> Interesting! This thread, right? >>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>> >>>> I haven't tried this as a patch to base, but I'm certain that the core >>>> of the proposal has no extra dependencies. Note that the proposal isn't >>>> about stack traces in particular - that's just one application of being >>>> able to throw exceptions with extra information. >>>> >>>> Even if `throwTo` isn't modified to throw exceptions with stack traces, >>>> this functionality could be provided outside of `Control.Exception` >>>> (though, that does seem like the right place to put it). I'm surprised >>>> that the circularity was so problematic, though. Why isn't it sufficient >>>> to have an hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>> >>>> -Michael >>>> >>>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald < >>>> carter.schonwald at gmail.com> wrote: >>>> >>>>> Hey Michael, >>>>> I actually proposed something along these lines that got OK'd by >>>>> libraries early this past fall, the main challenge we hit was actually >>>>> doing the enginering to add the stack traces to exceptions! theres some >>>>> nasty module cycles in base that happen when you try to weave things around >>>>> so that the standard error "message here" call includes some stack trace >>>>> info. Have you tried to do that simple starter patch to base? >>>>> >>>>> Chris Allen and I spent like 2 days trying to get it to work and just >>>>> gave up because of the cycles. We (and others) would probably love some >>>>> headway on that front. >>>>> >>>>> Theres also some in progress work to use the dwarf debugging info data >>>>> in >7.10 to provide useful stack traces in the default builds for GHC >>>>> afaik, 'cause the stack trace functionality you're pointing at currenlty >>>>> only work on profiled builds >>>>> >>>>> cheers >>>>> -Carter >>>>> >>>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >>>>> wrote: >>>>> >>>>>> Control.Exception currently lacks a good way to supply extra >>>>>> information along with exceptions. For example, exceptions could be >>>>>> thrown along with their callstack[1] or implicit stack[2], but we have >>>>>> no generic way to include this information with exceptions. >>>>>> >>>>>> Proposed Solution >>>>>> ================= >>>>>> >>>>>> The proposed solution is to add a list of `SomeExceptionInfo` to the >>>>>> `SomeException` datatype. This list stores additional information >>>>>> about the exception. These `ExceptionInfo` instances use a mechanism >>>>>> which is pretty much identical to the dynamic way the `Exception` type >>>>>> works: >>>>>> >>>>>> data SomeException = forall e . Exception e => >>>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>> >>>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>> SomeExceptionInfo a >>>>>> >>>>>> class Typeable a => ExceptionInfo a where >>>>>> displayExceptionInfo :: a -> String >>>>>> >>>>>> addExceptionInfo >>>>>> :: (ExceptionInfo a, Exception e) >>>>>> => a -> e -> SomeException >>>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >>>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>> >>>>>> `ExceptionInfo` lacks the to / from functions that `Exception` has, >>>>>> because I don't see much point in supporting a hierarchy for exception >>>>>> info. The `Typeable` superclass constraint supplies the necessary >>>>>> casting. >>>>>> >>>>>> `SomeExceptionInfo` could validly instead just use the constraint >>>>>> `(Typeable a, Show a)`. However, I believe it's good to have a new >>>>>> class for this so that: >>>>>> >>>>>> * The user can specify a custom `displayExceptionInfo` >>>>>> implementation, for when this extra info is presented to the user. >>>>>> This function would be invoked by the `show` implementation for >>>>>> `SomeException`. >>>>>> >>>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>>> Similarly to exceptions, I imagine that a type with a >>>>>> `ExceptionInfo` instance won't be used for anything but acting as >>>>>> such an annotation. Having a class for this allows you to ask GHCI >>>>>> about all in-scope exception info types via `:info ExceptionInfo`. >>>>>> >>>>>> Backwards Compatibility >>>>>> ======================= >>>>>> >>>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This means >>>>>> that this change could be made without breaking code: >>>>>> >>>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>> >>>>>> Note that consumers of this do not need to enable `-XPatternSynonyms`. >>>>>> >>>>>> Applications >>>>>> ============ >>>>>> >>>>>> Callstacks >>>>>> ---------- >>>>>> >>>>>> As mentioned at the beginning, this can be used to add callstacks to >>>>>> exceptions: >>>>>> >>>>>> newtype ExceptionCallStack = >>>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>>> deriving Typeable >>>>>> >>>>>> instance ExceptionInfo ExceptionCallStack where >>>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>> >>>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>> throwIOWithStack e = do >>>>>> stack <- currentCallStack >>>>>> if null stack >>>>>> then throwIO e >>>>>> else throwIO (addExceptionInfo (ExceptionCallStack stack) >>>>>> e) >>>>>> >>>>>> I see little downside for making something like this the default >>>>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>>>>> would add an additional stacktrace to its annotation, much like the >>>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>> stacktraces would be associated with the exception, rather than just >>>>>> listing locations that exceptions were thrown. This makes it >>>>>> tractable to debug exceptions that occur in concurrent programs, or in >>>>>> programs which frequently throw exceptions during normal functioning. >>>>>> >>>>>> Throwing Exceptions in Handlers >>>>>> ------------------------------- >>>>>> >>>>>> Example: >>>>>> >>>>>> main = >>>>>> throwIO InformativeErrorMessage `finally` >>>>>> throwIO ObscureCleanupIssue >>>>>> >>>>>> While `InformativeErrorMessage` got thrown, the user doesn't see it, >>>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>>>>> issues: >>>>>> >>>>>> 1. If the exception is handled by the default handler and yielded to >>>>>> the user, then the more informative error is lost. >>>>>> >>>>>> 2. Callers who expect to catch the "Informative error message" won't >>>>>> run their handlers for this exception type. >>>>>> >>>>>> Problem 1 can now easily be resolved by adding some info to the >>>>>> exception: >>>>>> >>>>>> data ExceptionCause = ExceptionCause >>>>>> { unExceptionCause :: SomeException } >>>>>> deriving Typeable >>>>>> >>>>>> instance ExceptionInfo ExceptionCause where >>>>>> displayExceptionInfo fe = >>>>>> "thrown while handling " ++ >>>>>> displayException (unExceptionCause fe) >>>>>> >>>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>> catch f g = f `oldCatch` handler >>>>>> where >>>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>>> throwIO (addExceptionInfo info ex') >>>>>> where >>>>>> info = ExceptionCause (toException ex) >>>>>> >>>>>> This implementation of `catch` is written in a backwards-compatible >>>>>> way, such that the exception thrown during finalization is still the >>>>>> one that gets rethrown. The "original" exception is recorded in the >>>>>> added info. This is the same approach used by Python 3's >>>>>> `__context__` attribute[3]. This was brought to my attention in a >>>>>> post by Mike Meyer[4], in a thread about having bracket not suppress >>>>>> the original exception[5]. >>>>>> >>>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>> compatibility. With the earlier example, a `catch` handler for >>>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>>>> exception being rethrown. This can be resolved by having a variant of >>>>>> catch which instead throws the original exception. This might be a >>>>>> good default for finalization handlers like `bracket` and `finally`. >>>>>> >>>>>> Asynchronous Exceptions >>>>>> ----------------------- >>>>>> >>>>>> Currently, the only reliable way to catch exceptions, ignoring async >>>>>> exceptions, is to fork a new thread. This is the approach used by the >>>>>> enclosed-exceptions[6] package. I think it's quite ugly that we need >>>>>> to go to such lengths due to the lack of one bit of information about >>>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>> >>>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't enforce >>>>>> anything. Any exception can be thrown as a sync or async exception. >>>>>> Instead, we ought to have a reliable way to know if an exception is >>>>>> synchronous or asynchronous. Here's what this would look like: >>>>>> >>>>>> data IsAsync = IsAsync >>>>>> deriving (Typeable, Show) >>>>>> >>>>>> instance ExceptionInfo IsAsync where >>>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>>> >>>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>> >>>>>> The details of this get a bit tricky: What happens if `throwIO` is >>>>>> used to rethrow a `SomeException` which has this `IsAsync` flag set? >>>>>> I'm going to leave out my thoughts on this for now as the interactions >>>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>> exceptions. Such details are explained in a post by Edsko de Vries[8] >>>>>> and ghc trac #2558[9]. >>>>>> >>>>>> Issue: fromException loses info >>>>>> =============================== >>>>>> >>>>>> I can think of one main non-ideal aspect of this proposal: >>>>>> >>>>>> Currently, the `toException` and `fromException` methods usually form >>>>>> a prism. In other words, when `fromException` yields a `Just`, you >>>>>> should get the same `SomeException` when using `toException` on that >>>>>> value. >>>>>> >>>>>> For example, >>>>>> >>>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex >>>>>> >>>>>> is equivalent to >>>>>> >>>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>>> >>>>>> However, with exception info added to just `SomeException`, and no >>>>>> changes to existing `Exception` instances, this >>>>>> doesn't hold. Exceptions caught as a specific exception type get >>>>>> rethrown with less information. >>>>>> >>>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a field >>>>>> to existing `Exception` instances. This would require the use of >>>>>> non-default implementations of the `toException` and `fromException` >>>>>> instances. >>>>>> >>>>>> Another approach is to have variants of `catch` and `throw` which also >>>>>> pass around the `[SomeExceptionInfo]`. >>>>>> >>>>>> [1] >>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>> [2] >>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>> [4] >>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>> [5] >>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>> >>>>>> _______________________________________________ >>>>>> Libraries mailing list >>>>>> Libraries at haskell.org >>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> >>>>>> >>>>> >>>> >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gale at sefer.org Tue Apr 21 09:05:07 2015 From: gale at sefer.org (Yitzchak Gale) Date: Tue, 21 Apr 2015 12:05:07 +0300 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Michael Snoyman wrote: > Sorry to confuse this thread with a second Michael. > > 1) there's a very good use case that's currently excluded by the > API, and (2) Michael Sloan figured out some great ways to minimize the > breakage. You could even argue that this proposal has *no* API breakage. Perhaps I missed it, but wouldn't this create major breakage across hackage for 7.8 and before? We will certainly be using 7.8 for years to come, at least for older versions of our products that we must continue to support. In fact, we are only now able to reduce our use of 7.6 to a fairly low (but non-zero) level. This cycle will likely be even longer than usual for the 7.10 upgrade due to the inclusion of the FTP breaking changes which make upgrading much more difficult. I certainly hope that most of the ecosystem will continue to support GHC versions going back at least one or two major versions, as it always has in the past. All that said, I am in favor of this change - it is a great design. But I would strongly oppose doing it immediately unless there is some plan to allow continued support of recent pre-7.10 GHC versions in the ecosystem. Thanks, Yitz ("you can call me Michael") From michael at snoyman.com Tue Apr 21 09:12:00 2015 From: michael at snoyman.com (Michael Snoyman) Date: Tue, 21 Apr 2015 09:12:00 +0000 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Tue, Apr 21, 2015 at 12:05 PM Yitzchak Gale wrote: > Michael Snoyman wrote: > > Sorry to confuse this thread with a second Michael. > > > > 1) there's a very good use case that's currently excluded by the > > API, and (2) Michael Sloan figured out some great ways to minimize the > > breakage. You could even argue that this proposal has *no* API breakage. > > Perhaps I missed it, but wouldn't this create major breakage > across hackage for 7.8 and before? > > We will certainly be using 7.8 for years to come, at least for > older versions of our products that we must continue to > support. In fact, we are only now able to reduce > our use of 7.6 to a fairly low (but non-zero) level. > > This cycle will likely be even longer than usual for the > 7.10 upgrade due to the inclusion of the FTP breaking > changes which make upgrading much more difficult. > > I certainly hope that most of the ecosystem will continue > to support GHC versions going back at least one or two > major versions, as it always has in the past. > > All that said, I am in favor of this change - it is a great > design. But I would strongly oppose doing it immediately > unless there is some plan to allow continued support > of recent pre-7.10 GHC versions in the ecosystem. > > Thanks, > Yitz ("you can call me Michael") > I may also be missing something here, but my read of Michael Sloan's proposal would mean that code written against the GHC 7.8/7.10 (and prior) API would continue to compile against GHC 7.12 and forward. It's true that code using the new functionality added in 7.12 would be unable to compile with 7.10 and earlier, but that's always the case when expanding the API (making this backwards compatible, or in PVP terms a minor version bump). The only catch here is that the proposal simulates the old API by using pattern synonyms. That means that the data types have in fact changed. But I'm so far unable to come up with an example that compiles with 7.8/7.10 but not with this new API (with the caveat that I'm no expert in pattern synonyms and therefore I may be misunderstanding something). I may also not be addressing what you're thinking of as the "major breakage." If so, can you clarify? Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From gale at sefer.org Tue Apr 21 12:47:55 2015 From: gale at sefer.org (Yitzchak Gale) Date: Tue, 21 Apr 2015 15:47:55 +0300 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Michael Snoyman wrote: > I may also be missing something here, but my read of Michael Sloan's > proposal would mean that code written against the GHC 7.8/7.10 (and prior) > API would continue to compile against GHC 7.12 and forward. It's true that > code using the new functionality added in 7.12 would be unable to compile > with 7.10 and earlier, but that's always the case when expanding the API > (making this backwards compatible, or in PVP terms a minor version bump)... > > I may also not be addressing what you're thinking of as the "major > breakage." If so, can you clarify? You're right, "major breakage" was not the right term. What's worrying me is that since so many libraries depend on exceptions, a sudden breaking change like this would prevent new versions of almost any library from being used with 7.8. So, for example, critical security fixes could not be applied. In short, it would make 7.8 very fragile or even unusable very quickly, which would indeed be "major breakage" for those of us who will be needing to use it for the medium term. Is there some way that backwards compatibility could somehow be achieved without the requirement of a new extension like PatternSynonyms, even though that might be the prettiest way? One obvious way would be to use a new name for the new SomeException, or perhaps just a different module name, and export only a smart constructor for the new type. That way there could be a compatibility library in which the smart constructor discards the ExceptionInfo and returns the old type. That would work going way back. Or perhaps something could be done with other fancier type features already present in 7.8, in a way that would then allow us to move to Michael Sl.'s nice PatternSynonym solution in 7.14. Thanks, Yitz From michael at snoyman.com Tue Apr 21 13:53:51 2015 From: michael at snoyman.com (Michael Snoyman) Date: Tue, 21 Apr 2015 13:53:51 +0000 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Tue, Apr 21, 2015 at 3:48 PM Yitzchak Gale wrote: > Michael Snoyman wrote: > > I may also be missing something here, but my read of Michael Sloan's > > proposal would mean that code written against the GHC 7.8/7.10 (and > prior) > > API would continue to compile against GHC 7.12 and forward. It's true > that > > code using the new functionality added in 7.12 would be unable to compile > > with 7.10 and earlier, but that's always the case when expanding the API > > (making this backwards compatible, or in PVP terms a minor version > bump)... > > > > I may also not be addressing what you're thinking of as the "major > > breakage." If so, can you clarify? > > You're right, "major breakage" was not the right term. > > What's worrying me is that since so many libraries depend on exceptions, > a sudden breaking change like this would prevent new versions of > almost any library from being used with 7.8. So, for example, critical > security fixes could not be applied. > > In short, it would make 7.8 very fragile or even unusable very > quickly, which would indeed be "major breakage" for those of > us who will be needing to use it for the medium term. > > Is there some way that backwards compatibility could somehow > be achieved without the requirement of a new extension like > PatternSynonyms, even though that might be the prettiest way? > > One obvious way would be to use a new name for the new > SomeException, or perhaps just a different module name, > and export only a smart constructor for the new type. That > way there could be a compatibility library in which the smart > constructor discards the ExceptionInfo and returns the old type. > That would work going way back. > > Or perhaps something could be done with other fancier > type features already present in 7.8, in a way that would > then allow us to move to Michael Sl.'s nice PatternSynonym > solution in 7.14. > > Thanks, > Yitz > Can you give an example of a concrete problem you're expecting to run into? I'm not seeing it. End users aren't using pattern synonyms in this proposal, it's an implementation detail of Control.Exception. MIchael -------------- next part -------------- An HTML attachment was scrubbed... URL: From gale at sefer.org Tue Apr 21 14:56:31 2015 From: gale at sefer.org (Yitzchak Gale) Date: Tue, 21 Apr 2015 17:56:31 +0300 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Michael Snoyman wrote: > Can you give an example of a concrete problem you're > expecting to run into? Package foo uploads a new version with a critical bug fix. As is often the case, this new version also supports updated dependencies, including exceptions. The new exceptions breaks the old SomeException type, so foo is forced to specify a lower bound that excludes the old exceptions. I depend on foo and I need to compile using GHC 7.8. Can I get this critical bug fix for foo? We can't always prevent this kind of scenario. And when it does happen in an isolated case, there are work-arounds. But for a ubiquitous dependency like exceptions, this single breaking change would effectively block future upgrades of a significant proportion of Hackage for GHC 7.8. From greg at gregweber.info Tue Apr 21 15:23:24 2015 From: greg at gregweber.info (Greg Weber) Date: Tue, 21 Apr 2015 08:23:24 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Tue, Apr 14, 2015 at 11:38 AM, Michael Sloan wrote: > data SomeException = forall e . Exception e => > SomeExceptionWithInfo e [SomeExceptionInfo] > > data SomeExceptionInfo = forall a . ExceptionInfo a => > SomeExceptionInfo a Is it necessary for SomeExceptionWithInfo to have a list of a forall data type? Are Exceptions really that mysterious, or can we more concretely describe the information that should be attached to an exception? SomeExceptionWithInfo e IsAsync CallStack ImplicitStack I am still open to the idea of adding a forall data scratchpad, but can we at least try to specify some standard fields? SomeExceptionWithInfo e IsAsync CallStack ImplicitStack [SomeExceptionInfo] -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Tue Apr 21 15:52:20 2015 From: michael at snoyman.com (Michael Snoyman) Date: Tue, 21 Apr 2015 15:52:20 +0000 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Tue, Apr 21, 2015 at 5:56 PM Yitzchak Gale wrote: > Michael Snoyman wrote: > > Can you give an example of a concrete problem you're > > expecting to run into? > > Package foo uploads a new version with a critical bug fix. > As is often the case, this new version also supports updated > dependencies, including exceptions. The new exceptions > breaks the old SomeException type, so foo is forced to > specify a lower bound that excludes the old exceptions. > > But that's the scenario I'm asking for more information on. Can you clarify what you're describing here? I'm not seeing a situation where an author couldn't easily be compatible with GHC <=7.8 by sticking to the old API? > I depend on foo and I need to compile using GHC 7.8. > Can I get this critical bug fix for foo? > > We can't always prevent this kind of scenario. > And when it does happen in an isolated case, there > are work-arounds. But for a ubiquitous dependency > like exceptions, this single breaking change would > effectively block future upgrades of a significant proportion > of Hackage for GHC 7.8. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From felipe.lessa at gmail.com Tue Apr 21 19:09:17 2015 From: felipe.lessa at gmail.com (Felipe Lessa) Date: Tue, 21 Apr 2015 16:09:17 -0300 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: <5536A05D.5@gmail.com> I'm +1 on this proposal. On 21-04-2015 12:52, Michael Snoyman wrote: > On Tue, Apr 21, 2015 at 5:56 PM Yitzchak Gale > wrote: > > Michael Snoyman wrote: > > Can you give an example of a concrete problem you're > > expecting to run into? > > Package foo uploads a new version with a critical bug fix. > As is often the case, this new version also supports updated > dependencies, including exceptions. The new exceptions > breaks the old SomeException type, so foo is forced to > specify a lower bound that excludes the old exceptions. > > > But that's the scenario I'm asking for more information on. Can you > clarify what you're describing here? I'm not seeing a situation where an > author couldn't easily be compatible with GHC <=7.8 by sticking to the > old API? I think Michael Gale is thinking about an author that may end up using the new SomeExceptionWithInfo constructor for some reason, thus leaving older GHCs out of any new updates. However, IIUC, this would cause problems for GHC < 7.12, not only GHC < 7.10, since you won't be able to use GHC 7.12's base package on GHC 7.10. So perhaps I'm misunderstanding the issue as well. Cheers, -- Michael Lessa. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From mgsloan at gmail.com Tue Apr 21 20:37:06 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 13:37:06 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > if you can patch prelude error to include stack traces, i will owe you a > >=1 beer each at the next two icfps. Thats all i want for christmas. :) > Sounds good! No promises, but I'll be giving this a try soon. Looking forward to ICFP beers either way :D i can't speak for how a different patch might work out, because thats not > what I'd tried at the time. If you have a go, please share the results! > -Carter > > On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan wrote: > >> Hi Carter! >> >> Interesting! This thread, right? >> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >> >> I haven't tried this as a patch to base, but I'm certain that the core of >> the proposal has no extra dependencies. Note that the proposal isn't about >> stack traces in particular - that's just one application of being able to >> throw exceptions with extra information. >> >> Even if `throwTo` isn't modified to throw exceptions with stack traces, >> this functionality could be provided outside of `Control.Exception` >> (though, that does seem like the right place to put it). I'm surprised >> that the circularity was so problematic, though. Why isn't it sufficient >> to have an hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >> >> -Michael >> >> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> Hey Michael, >>> I actually proposed something along these lines that got OK'd by >>> libraries early this past fall, the main challenge we hit was actually >>> doing the enginering to add the stack traces to exceptions! theres some >>> nasty module cycles in base that happen when you try to weave things around >>> so that the standard error "message here" call includes some stack trace >>> info. Have you tried to do that simple starter patch to base? >>> >>> Chris Allen and I spent like 2 days trying to get it to work and just >>> gave up because of the cycles. We (and others) would probably love some >>> headway on that front. >>> >>> Theres also some in progress work to use the dwarf debugging info data >>> in >7.10 to provide useful stack traces in the default builds for GHC >>> afaik, 'cause the stack trace functionality you're pointing at currenlty >>> only work on profiled builds >>> >>> cheers >>> -Carter >>> >>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >>> wrote: >>> >>>> Control.Exception currently lacks a good way to supply extra >>>> information along with exceptions. For example, exceptions could be >>>> thrown along with their callstack[1] or implicit stack[2], but we have >>>> no generic way to include this information with exceptions. >>>> >>>> Proposed Solution >>>> ================= >>>> >>>> The proposed solution is to add a list of `SomeExceptionInfo` to the >>>> `SomeException` datatype. This list stores additional information >>>> about the exception. These `ExceptionInfo` instances use a mechanism >>>> which is pretty much identical to the dynamic way the `Exception` type >>>> works: >>>> >>>> data SomeException = forall e . Exception e => >>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>> >>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>> SomeExceptionInfo a >>>> >>>> class Typeable a => ExceptionInfo a where >>>> displayExceptionInfo :: a -> String >>>> >>>> addExceptionInfo >>>> :: (ExceptionInfo a, Exception e) >>>> => a -> e -> SomeException >>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>> >>>> `ExceptionInfo` lacks the to / from functions that `Exception` has, >>>> because I don't see much point in supporting a hierarchy for exception >>>> info. The `Typeable` superclass constraint supplies the necessary >>>> casting. >>>> >>>> `SomeExceptionInfo` could validly instead just use the constraint >>>> `(Typeable a, Show a)`. However, I believe it's good to have a new >>>> class for this so that: >>>> >>>> * The user can specify a custom `displayExceptionInfo` >>>> implementation, for when this extra info is presented to the user. >>>> This function would be invoked by the `show` implementation for >>>> `SomeException`. >>>> >>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>> Similarly to exceptions, I imagine that a type with a >>>> `ExceptionInfo` instance won't be used for anything but acting as >>>> such an annotation. Having a class for this allows you to ask GHCI >>>> about all in-scope exception info types via `:info ExceptionInfo`. >>>> >>>> Backwards Compatibility >>>> ======================= >>>> >>>> GHC 7.10 adds support for bidirectional pattern synonyms. This means >>>> that this change could be made without breaking code: >>>> >>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>> SomeException x = SomeExceptionWithInfo x [] >>>> >>>> Note that consumers of this do not need to enable `-XPatternSynonyms`. >>>> >>>> Applications >>>> ============ >>>> >>>> Callstacks >>>> ---------- >>>> >>>> As mentioned at the beginning, this can be used to add callstacks to >>>> exceptions: >>>> >>>> newtype ExceptionCallStack = >>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>> deriving Typeable >>>> >>>> instance ExceptionInfo ExceptionCallStack where >>>> displayExceptionInfo = unlines . unExceptionCallStack >>>> >>>> throwIOWithStack :: Exception e => e -> IO a >>>> throwIOWithStack e = do >>>> stack <- currentCallStack >>>> if null stack >>>> then throwIO e >>>> else throwIO (addExceptionInfo (ExceptionCallStack stack) e) >>>> >>>> I see little downside for making something like this the default >>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>>> would add an additional stacktrace to its annotation, much like the >>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>> stacktraces would be associated with the exception, rather than just >>>> listing locations that exceptions were thrown. This makes it >>>> tractable to debug exceptions that occur in concurrent programs, or in >>>> programs which frequently throw exceptions during normal functioning. >>>> >>>> Throwing Exceptions in Handlers >>>> ------------------------------- >>>> >>>> Example: >>>> >>>> main = >>>> throwIO InformativeErrorMessage `finally` >>>> throwIO ObscureCleanupIssue >>>> >>>> While `InformativeErrorMessage` got thrown, the user doesn't see it, >>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>>> issues: >>>> >>>> 1. If the exception is handled by the default handler and yielded to >>>> the user, then the more informative error is lost. >>>> >>>> 2. Callers who expect to catch the "Informative error message" won't >>>> run their handlers for this exception type. >>>> >>>> Problem 1 can now easily be resolved by adding some info to the >>>> exception: >>>> >>>> data ExceptionCause = ExceptionCause >>>> { unExceptionCause :: SomeException } >>>> deriving Typeable >>>> >>>> instance ExceptionInfo ExceptionCause where >>>> displayExceptionInfo fe = >>>> "thrown while handling " ++ >>>> displayException (unExceptionCause fe) >>>> >>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>> catch f g = f `oldCatch` handler >>>> where >>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>> throwIO (addExceptionInfo info ex') >>>> where >>>> info = ExceptionCause (toException ex) >>>> >>>> This implementation of `catch` is written in a backwards-compatible >>>> way, such that the exception thrown during finalization is still the >>>> one that gets rethrown. The "original" exception is recorded in the >>>> added info. This is the same approach used by Python 3's >>>> `__context__` attribute[3]. This was brought to my attention in a >>>> post by Mike Meyer[4], in a thread about having bracket not suppress >>>> the original exception[5]. >>>> >>>> This doesn't directly resolve issue #2, due to this backwards >>>> compatibility. With the earlier example, a `catch` handler for >>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>> exception being rethrown. This can be resolved by having a variant of >>>> catch which instead throws the original exception. This might be a >>>> good default for finalization handlers like `bracket` and `finally`. >>>> >>>> Asynchronous Exceptions >>>> ----------------------- >>>> >>>> Currently, the only reliable way to catch exceptions, ignoring async >>>> exceptions, is to fork a new thread. This is the approach used by the >>>> enclosed-exceptions[6] package. I think it's quite ugly that we need >>>> to go to such lengths due to the lack of one bit of information about >>>> the exception! This would resolve ghc trac #5902[7]. >>>> >>>> base-4.7 added the `SomeAsyncException` type, but this doesn't enforce >>>> anything. Any exception can be thrown as a sync or async exception. >>>> Instead, we ought to have a reliable way to know if an exception is >>>> synchronous or asynchronous. Here's what this would look like: >>>> >>>> data IsAsync = IsAsync >>>> deriving (Typeable, Show) >>>> >>>> instance ExceptionInfo IsAsync where >>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>> >>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>> >>>> The details of this get a bit tricky: What happens if `throwIO` is >>>> used to rethrow a `SomeException` which has this `IsAsync` flag set? >>>> I'm going to leave out my thoughts on this for now as the interactions >>>> between unsafePerformIO and the concept of "rethrowing" async >>>> exceptions. Such details are explained in a post by Edsko de Vries[8] >>>> and ghc trac #2558[9]. >>>> >>>> Issue: fromException loses info >>>> =============================== >>>> >>>> I can think of one main non-ideal aspect of this proposal: >>>> >>>> Currently, the `toException` and `fromException` methods usually form >>>> a prism. In other words, when `fromException` yields a `Just`, you >>>> should get the same `SomeException` when using `toException` on that >>>> value. >>>> >>>> For example, >>>> >>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex >>>> >>>> is equivalent to >>>> >>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>> >>>> However, with exception info added to just `SomeException`, and no >>>> changes to existing `Exception` instances, this >>>> doesn't hold. Exceptions caught as a specific exception type get >>>> rethrown with less information. >>>> >>>> One resolution to this is be to add `[SomeExceptionInfo]` as a field >>>> to existing `Exception` instances. This would require the use of >>>> non-default implementations of the `toException` and `fromException` >>>> instances. >>>> >>>> Another approach is to have variants of `catch` and `throw` which also >>>> pass around the `[SomeExceptionInfo]`. >>>> >>>> [1] >>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>> [2] >>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>> [4] >>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>> [5] >>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>> >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Tue Apr 21 20:55:28 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 13:55:28 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Tue, Apr 21, 2015 at 8:23 AM, Greg Weber wrote: > > On Tue, Apr 14, 2015 at 11:38 AM, Michael Sloan wrote: > >> data SomeException = forall e . Exception e => >> SomeExceptionWithInfo e [SomeExceptionInfo] >> >> data SomeExceptionInfo = forall a . ExceptionInfo a => >> SomeExceptionInfo a > > > Is it necessary for SomeExceptionWithInfo to have a list of a forall data > type? > Are Exceptions really that mysterious, or can we more concretely describe > the information that should be attached to an exception? > > SomeExceptionWithInfo e IsAsync CallStack ImplicitStack > I did consider this option, but I think as soon as a fixed set is selected, someone's going to put something else in it. Usually we wouldn't want to use such a 'dynamic' mechanism in Haskell, but it's appropriate for something so global as the type used to throw exceptions. > I am still open to the idea of adding a forall data scratchpad, but can we > at least try to specify some standard fields? > > SomeExceptionWithInfo e IsAsync CallStack ImplicitStack > [SomeExceptionInfo] > This is an interesting idea. I particularly see value in having 'IsAsync' be a part of the Exception. This is because `throwIO` / `throw` would need to set this to False when rethrowing async exceptions. -------------- next part -------------- An HTML attachment was scrubbed... URL: From qdunkan at gmail.com Tue Apr 21 20:55:52 2015 From: qdunkan at gmail.com (Evan Laforge) Date: Tue, 21 Apr 2015 13:55:52 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Maybe I'm missing something, but isn't this already implemented? https://phabricator.haskell.org/D578 On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan wrote: > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald > wrote: >> >> if you can patch prelude error to include stack traces, i will owe you a >> >=1 beer each at the next two icfps. Thats all i want for christmas. :) > > > Sounds good! No promises, but I'll be giving this a try soon. Looking > forward to ICFP beers either way :D > >> i can't speak for how a different patch might work out, because thats not >> what I'd tried at the time. If you have a go, please share the results! >> -Carter >> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan wrote: >>> >>> Hi Carter! >>> >>> Interesting! This thread, right? >>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>> >>> I haven't tried this as a patch to base, but I'm certain that the core of >>> the proposal has no extra dependencies. Note that the proposal isn't about >>> stack traces in particular - that's just one application of being able to >>> throw exceptions with extra information. >>> >>> Even if `throwTo` isn't modified to throw exceptions with stack traces, >>> this functionality could be provided outside of `Control.Exception` (though, >>> that does seem like the right place to put it). I'm surprised that the >>> circularity was so problematic, though. Why isn't it sufficient to have an >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>> >>> -Michael >>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>> wrote: >>>> >>>> Hey Michael, >>>> I actually proposed something along these lines that got OK'd by >>>> libraries early this past fall, the main challenge we hit was actually doing >>>> the enginering to add the stack traces to exceptions! theres some nasty >>>> module cycles in base that happen when you try to weave things around so >>>> that the standard error "message here" call includes some stack trace info. >>>> Have you tried to do that simple starter patch to base? >>>> >>>> Chris Allen and I spent like 2 days trying to get it to work and just >>>> gave up because of the cycles. We (and others) would probably love some >>>> headway on that front. >>>> >>>> Theres also some in progress work to use the dwarf debugging info data >>>> in >7.10 to provide useful stack traces in the default builds for GHC afaik, >>>> 'cause the stack trace functionality you're pointing at currenlty only work >>>> on profiled builds >>>> >>>> cheers >>>> -Carter >>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >>>> wrote: >>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>> information along with exceptions. For example, exceptions could be >>>>> thrown along with their callstack[1] or implicit stack[2], but we have >>>>> no generic way to include this information with exceptions. >>>>> >>>>> Proposed Solution >>>>> ================= >>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` to the >>>>> `SomeException` datatype. This list stores additional information >>>>> about the exception. These `ExceptionInfo` instances use a mechanism >>>>> which is pretty much identical to the dynamic way the `Exception` type >>>>> works: >>>>> >>>>> data SomeException = forall e . Exception e => >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>> SomeExceptionInfo a >>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>> displayExceptionInfo :: a -> String >>>>> >>>>> addExceptionInfo >>>>> :: (ExceptionInfo a, Exception e) >>>>> => a -> e -> SomeException >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` has, >>>>> because I don't see much point in supporting a hierarchy for exception >>>>> info. The `Typeable` superclass constraint supplies the necessary >>>>> casting. >>>>> >>>>> `SomeExceptionInfo` could validly instead just use the constraint >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a new >>>>> class for this so that: >>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>> implementation, for when this extra info is presented to the user. >>>>> This function would be invoked by the `show` implementation for >>>>> `SomeException`. >>>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>> Similarly to exceptions, I imagine that a type with a >>>>> `ExceptionInfo` instance won't be used for anything but acting as >>>>> such an annotation. Having a class for this allows you to ask GHCI >>>>> about all in-scope exception info types via `:info ExceptionInfo`. >>>>> >>>>> Backwards Compatibility >>>>> ======================= >>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This means >>>>> that this change could be made without breaking code: >>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>> >>>>> Note that consumers of this do not need to enable `-XPatternSynonyms`. >>>>> >>>>> Applications >>>>> ============ >>>>> >>>>> Callstacks >>>>> ---------- >>>>> >>>>> As mentioned at the beginning, this can be used to add callstacks to >>>>> exceptions: >>>>> >>>>> newtype ExceptionCallStack = >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>> deriving Typeable >>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>> throwIOWithStack e = do >>>>> stack <- currentCallStack >>>>> if null stack >>>>> then throwIO e >>>>> else throwIO (addExceptionInfo (ExceptionCallStack stack) >>>>> e) >>>>> >>>>> I see little downside for making something like this the default >>>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>>>> would add an additional stacktrace to its annotation, much like the >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>> stacktraces would be associated with the exception, rather than just >>>>> listing locations that exceptions were thrown. This makes it >>>>> tractable to debug exceptions that occur in concurrent programs, or in >>>>> programs which frequently throw exceptions during normal functioning. >>>>> >>>>> Throwing Exceptions in Handlers >>>>> ------------------------------- >>>>> >>>>> Example: >>>>> >>>>> main = >>>>> throwIO InformativeErrorMessage `finally` >>>>> throwIO ObscureCleanupIssue >>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't see it, >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>>>> issues: >>>>> >>>>> 1. If the exception is handled by the default handler and yielded to >>>>> the user, then the more informative error is lost. >>>>> >>>>> 2. Callers who expect to catch the "Informative error message" won't >>>>> run their handlers for this exception type. >>>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>>> exception: >>>>> >>>>> data ExceptionCause = ExceptionCause >>>>> { unExceptionCause :: SomeException } >>>>> deriving Typeable >>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>> displayExceptionInfo fe = >>>>> "thrown while handling " ++ >>>>> displayException (unExceptionCause fe) >>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>> catch f g = f `oldCatch` handler >>>>> where >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>> throwIO (addExceptionInfo info ex') >>>>> where >>>>> info = ExceptionCause (toException ex) >>>>> >>>>> This implementation of `catch` is written in a backwards-compatible >>>>> way, such that the exception thrown during finalization is still the >>>>> one that gets rethrown. The "original" exception is recorded in the >>>>> added info. This is the same approach used by Python 3's >>>>> `__context__` attribute[3]. This was brought to my attention in a >>>>> post by Mike Meyer[4], in a thread about having bracket not suppress >>>>> the original exception[5]. >>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>> compatibility. With the earlier example, a `catch` handler for >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>>> exception being rethrown. This can be resolved by having a variant of >>>>> catch which instead throws the original exception. This might be a >>>>> good default for finalization handlers like `bracket` and `finally`. >>>>> >>>>> Asynchronous Exceptions >>>>> ----------------------- >>>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring async >>>>> exceptions, is to fork a new thread. This is the approach used by the >>>>> enclosed-exceptions[6] package. I think it's quite ugly that we need >>>>> to go to such lengths due to the lack of one bit of information about >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't enforce >>>>> anything. Any exception can be thrown as a sync or async exception. >>>>> Instead, we ought to have a reliable way to know if an exception is >>>>> synchronous or asynchronous. Here's what this would look like: >>>>> >>>>> data IsAsync = IsAsync >>>>> deriving (Typeable, Show) >>>>> >>>>> instance ExceptionInfo IsAsync where >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>> >>>>> The details of this get a bit tricky: What happens if `throwIO` is >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag set? >>>>> I'm going to leave out my thoughts on this for now as the interactions >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>> exceptions. Such details are explained in a post by Edsko de Vries[8] >>>>> and ghc trac #2558[9]. >>>>> >>>>> Issue: fromException loses info >>>>> =============================== >>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>> >>>>> Currently, the `toException` and `fromException` methods usually form >>>>> a prism. In other words, when `fromException` yields a `Just`, you >>>>> should get the same `SomeException` when using `toException` on that >>>>> value. >>>>> >>>>> For example, >>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex >>>>> >>>>> is equivalent to >>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>> >>>>> However, with exception info added to just `SomeException`, and no >>>>> changes to existing `Exception` instances, this >>>>> doesn't hold. Exceptions caught as a specific exception type get >>>>> rethrown with less information. >>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a field >>>>> to existing `Exception` instances. This would require the use of >>>>> non-default implementations of the `toException` and `fromException` >>>>> instances. >>>>> >>>>> Another approach is to have variants of `catch` and `throw` which also >>>>> pass around the `[SomeExceptionInfo]`. >>>>> >>>>> [1] >>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>> [2] >>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>> [4] >>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>> [5] >>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>> >>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>> >>> >> > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > From mgsloan at gmail.com Tue Apr 21 21:04:06 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 14:04:06 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Hmm, that patch doesn't appear to add stack traces to 'Prelude.error', which is what Carter wants here. Also, I think it would be done with profiling callstacks rather than implicit callstacks. But it's certainly also useful to have functions which do the same with implicit callstacks! On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge wrote: > Maybe I'm missing something, but isn't this already implemented? > > https://phabricator.haskell.org/D578 > > On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan wrote: > > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald > > wrote: > >> > >> if you can patch prelude error to include stack traces, i will owe you a > >> >=1 beer each at the next two icfps. Thats all i want for christmas. :) > > > > > > Sounds good! No promises, but I'll be giving this a try soon. Looking > > forward to ICFP beers either way :D > > > >> i can't speak for how a different patch might work out, because thats > not > >> what I'd tried at the time. If you have a go, please share the results! > >> -Carter > >> > >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan > wrote: > >>> > >>> Hi Carter! > >>> > >>> Interesting! This thread, right? > >>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html > >>> > >>> I haven't tried this as a patch to base, but I'm certain that the core > of > >>> the proposal has no extra dependencies. Note that the proposal isn't > about > >>> stack traces in particular - that's just one application of being able > to > >>> throw exceptions with extra information. > >>> > >>> Even if `throwTo` isn't modified to throw exceptions with stack traces, > >>> this functionality could be provided outside of `Control.Exception` > (though, > >>> that does seem like the right place to put it). I'm surprised that the > >>> circularity was so problematic, though. Why isn't it sufficient to > have an > >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? > >>> > >>> -Michael > >>> > >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald > >>> wrote: > >>>> > >>>> Hey Michael, > >>>> I actually proposed something along these lines that got OK'd by > >>>> libraries early this past fall, the main challenge we hit was > actually doing > >>>> the enginering to add the stack traces to exceptions! theres some > nasty > >>>> module cycles in base that happen when you try to weave things around > so > >>>> that the standard error "message here" call includes some stack trace > info. > >>>> Have you tried to do that simple starter patch to base? > >>>> > >>>> Chris Allen and I spent like 2 days trying to get it to work and just > >>>> gave up because of the cycles. We (and others) would probably love > some > >>>> headway on that front. > >>>> > >>>> Theres also some in progress work to use the dwarf debugging info data > >>>> in >7.10 to provide useful stack traces in the default builds for GHC > afaik, > >>>> 'cause the stack trace functionality you're pointing at currenlty > only work > >>>> on profiled builds > >>>> > >>>> cheers > >>>> -Carter > >>>> > >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan > >>>> wrote: > >>>>> > >>>>> Control.Exception currently lacks a good way to supply extra > >>>>> information along with exceptions. For example, exceptions could be > >>>>> thrown along with their callstack[1] or implicit stack[2], but we > have > >>>>> no generic way to include this information with exceptions. > >>>>> > >>>>> Proposed Solution > >>>>> ================= > >>>>> > >>>>> The proposed solution is to add a list of `SomeExceptionInfo` to the > >>>>> `SomeException` datatype. This list stores additional information > >>>>> about the exception. These `ExceptionInfo` instances use a mechanism > >>>>> which is pretty much identical to the dynamic way the `Exception` > type > >>>>> works: > >>>>> > >>>>> data SomeException = forall e . Exception e => > >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] > >>>>> > >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => > >>>>> SomeExceptionInfo a > >>>>> > >>>>> class Typeable a => ExceptionInfo a where > >>>>> displayExceptionInfo :: a -> String > >>>>> > >>>>> addExceptionInfo > >>>>> :: (ExceptionInfo a, Exception e) > >>>>> => a -> e -> SomeException > >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = > >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) > >>>>> > >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` has, > >>>>> because I don't see much point in supporting a hierarchy for > exception > >>>>> info. The `Typeable` superclass constraint supplies the necessary > >>>>> casting. > >>>>> > >>>>> `SomeExceptionInfo` could validly instead just use the constraint > >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a new > >>>>> class for this so that: > >>>>> > >>>>> * The user can specify a custom `displayExceptionInfo` > >>>>> implementation, for when this extra info is presented to the user. > >>>>> This function would be invoked by the `show` implementation for > >>>>> `SomeException`. > >>>>> > >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. > >>>>> Similarly to exceptions, I imagine that a type with a > >>>>> `ExceptionInfo` instance won't be used for anything but acting as > >>>>> such an annotation. Having a class for this allows you to ask GHCI > >>>>> about all in-scope exception info types via `:info ExceptionInfo`. > >>>>> > >>>>> Backwards Compatibility > >>>>> ======================= > >>>>> > >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This means > >>>>> that this change could be made without breaking code: > >>>>> > >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where > >>>>> SomeException x = SomeExceptionWithInfo x [] > >>>>> > >>>>> Note that consumers of this do not need to enable > `-XPatternSynonyms`. > >>>>> > >>>>> Applications > >>>>> ============ > >>>>> > >>>>> Callstacks > >>>>> ---------- > >>>>> > >>>>> As mentioned at the beginning, this can be used to add callstacks to > >>>>> exceptions: > >>>>> > >>>>> newtype ExceptionCallStack = > >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } > >>>>> deriving Typeable > >>>>> > >>>>> instance ExceptionInfo ExceptionCallStack where > >>>>> displayExceptionInfo = unlines . unExceptionCallStack > >>>>> > >>>>> throwIOWithStack :: Exception e => e -> IO a > >>>>> throwIOWithStack e = do > >>>>> stack <- currentCallStack > >>>>> if null stack > >>>>> then throwIO e > >>>>> else throwIO (addExceptionInfo (ExceptionCallStack stack) > >>>>> e) > >>>>> > >>>>> I see little downside for making something like this the default > >>>>> implementation `throwIO`. Each rethrowing of the `SomeException` > >>>>> would add an additional stacktrace to its annotation, much like the > >>>>> output of `+RTS -xc`. Unlike this debug output, though, the > >>>>> stacktraces would be associated with the exception, rather than just > >>>>> listing locations that exceptions were thrown. This makes it > >>>>> tractable to debug exceptions that occur in concurrent programs, or > in > >>>>> programs which frequently throw exceptions during normal functioning. > >>>>> > >>>>> Throwing Exceptions in Handlers > >>>>> ------------------------------- > >>>>> > >>>>> Example: > >>>>> > >>>>> main = > >>>>> throwIO InformativeErrorMessage `finally` > >>>>> throwIO ObscureCleanupIssue > >>>>> > >>>>> While `InformativeErrorMessage` got thrown, the user doesn't see it, > >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few > >>>>> issues: > >>>>> > >>>>> 1. If the exception is handled by the default handler and yielded to > >>>>> the user, then the more informative error is lost. > >>>>> > >>>>> 2. Callers who expect to catch the "Informative error message" won't > >>>>> run their handlers for this exception type. > >>>>> > >>>>> Problem 1 can now easily be resolved by adding some info to the > >>>>> exception: > >>>>> > >>>>> data ExceptionCause = ExceptionCause > >>>>> { unExceptionCause :: SomeException } > >>>>> deriving Typeable > >>>>> > >>>>> instance ExceptionInfo ExceptionCause where > >>>>> displayExceptionInfo fe = > >>>>> "thrown while handling " ++ > >>>>> displayException (unExceptionCause fe) > >>>>> > >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a > >>>>> catch f g = f `oldCatch` handler > >>>>> where > >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> > >>>>> throwIO (addExceptionInfo info ex') > >>>>> where > >>>>> info = ExceptionCause (toException ex) > >>>>> > >>>>> This implementation of `catch` is written in a backwards-compatible > >>>>> way, such that the exception thrown during finalization is still the > >>>>> one that gets rethrown. The "original" exception is recorded in the > >>>>> added info. This is the same approach used by Python 3's > >>>>> `__context__` attribute[3]. This was brought to my attention in a > >>>>> post by Mike Meyer[4], in a thread about having bracket not suppress > >>>>> the original exception[5]. > >>>>> > >>>>> This doesn't directly resolve issue #2, due to this backwards > >>>>> compatibility. With the earlier example, a `catch` handler for > >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the > >>>>> exception being rethrown. This can be resolved by having a variant > of > >>>>> catch which instead throws the original exception. This might be a > >>>>> good default for finalization handlers like `bracket` and `finally`. > >>>>> > >>>>> Asynchronous Exceptions > >>>>> ----------------------- > >>>>> > >>>>> Currently, the only reliable way to catch exceptions, ignoring async > >>>>> exceptions, is to fork a new thread. This is the approach used by > the > >>>>> enclosed-exceptions[6] package. I think it's quite ugly that we need > >>>>> to go to such lengths due to the lack of one bit of information about > >>>>> the exception! This would resolve ghc trac #5902[7]. > >>>>> > >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't > enforce > >>>>> anything. Any exception can be thrown as a sync or async exception. > >>>>> Instead, we ought to have a reliable way to know if an exception is > >>>>> synchronous or asynchronous. Here's what this would look like: > >>>>> > >>>>> data IsAsync = IsAsync > >>>>> deriving (Typeable, Show) > >>>>> > >>>>> instance ExceptionInfo IsAsync where > >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" > >>>>> > >>>>> throwTo :: Exception e => ThreadId -> e -> IO () > >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync > >>>>> > >>>>> The details of this get a bit tricky: What happens if `throwIO` is > >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag set? > >>>>> I'm going to leave out my thoughts on this for now as the > interactions > >>>>> between unsafePerformIO and the concept of "rethrowing" async > >>>>> exceptions. Such details are explained in a post by Edsko de > Vries[8] > >>>>> and ghc trac #2558[9]. > >>>>> > >>>>> Issue: fromException loses info > >>>>> =============================== > >>>>> > >>>>> I can think of one main non-ideal aspect of this proposal: > >>>>> > >>>>> Currently, the `toException` and `fromException` methods usually form > >>>>> a prism. In other words, when `fromException` yields a `Just`, you > >>>>> should get the same `SomeException` when using `toException` on that > >>>>> value. > >>>>> > >>>>> For example, > >>>>> > >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO ex > >>>>> > >>>>> is equivalent to > >>>>> > >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex > >>>>> > >>>>> However, with exception info added to just `SomeException`, and no > >>>>> changes to existing `Exception` instances, this > >>>>> doesn't hold. Exceptions caught as a specific exception type get > >>>>> rethrown with less information. > >>>>> > >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a field > >>>>> to existing `Exception` instances. This would require the use of > >>>>> non-default implementations of the `toException` and `fromException` > >>>>> instances. > >>>>> > >>>>> Another approach is to have variants of `catch` and `throw` which > also > >>>>> pass around the `[SomeExceptionInfo]`. > >>>>> > >>>>> [1] > >>>>> > https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack > >>>>> [2] > >>>>> > https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations > >>>>> [3] https://www.python.org/dev/peps/pep-3134/ > >>>>> [4] > >>>>> > https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html > >>>>> [5] > >>>>> > https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html > >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions > >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 > >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ > >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 > >>>>> > >>>>> _______________________________________________ > >>>>> Libraries mailing list > >>>>> Libraries at haskell.org > >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > >>>>> > >>>> > >>> > >> > > > > > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From schernichkin at gmail.com Tue Apr 21 21:23:25 2015 From: schernichkin at gmail.com (=?UTF-8?B?0KHRgtCw0L3QuNGB0LvQsNCyINCn0LXRgNC90LjRh9C60LjQvQ==?=) Date: Wed, 22 Apr 2015 00:23:25 +0300 Subject: Proposal: add alterLookupWithKey to Data.Map.Lazy (containers) Message-ID: Github issue: https://github.com/haskell/containers/issues/151 Summary: add alterLookupWithKey :: Ord k => (k -> Maybe a -> Maybe a) -> k -> Map k a -> (Maybe a, Map k a) function to Data.Map.Lazy. Details: implement alterLookupWithKey function which takes an update function, key and map, allowing to insert, delete or update a value in a Map and return updated map with a new value. Motivations: For insert/update/delete: same as for alter :: Ord k => (Maybe a -> Maybe a) -> k -> Map k a -> Map k a - it allows to perform insert/update/delete within single lookup. For returning updated value: same as for *LookupWithKey functions - in case of update we mind be interested in the updated value. For a "key" parameter: hornestly, don't know. *LookupWithKey functions are having (k -> .. ) -> k -> -> Map k a -> (Maybe a, Map k a) signatures, but I don't see any reason to pass the key to the update function, because we always can capture the key in a closure if we whant to. The only reason is to respect existent conventions. Since we already have insertLookupWithKey and updateLookupWithKey functions it makes sence to implement alterLookupWithKey in the same way. -- Sincerely, Stanislav Chernichkin. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Tue Apr 21 21:32:55 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 14:32:55 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Tue, Apr 21, 2015 at 7:56 AM, Yitzchak Gale wrote: > Michael Snoyman wrote: > > Can you give an example of a concrete problem you're > > expecting to run into? > > Package foo uploads a new version with a critical bug fix. > As is often the case, this new version also supports updated > dependencies, including exceptions. The new exceptions > breaks the old SomeException type, so foo is forced to > specify a lower bound that excludes the old exceptions. > This only happens when a package depends on receiving or adding extra exception info. I don't think this will be necessary for most packages. The primary use-case I'm seeing for this extra exception info is being able to display it to the user. Since this will be done by 'displayException' / 'show' / the default exception handler, there's no need for user code to do anything special to get it. In the cases where we do have code that cares about this extra exception info, we would indeed be doing something that wasn't possible before, and so have issues with backwards compatibility. For example, when an exception is thrown while 'bracket' is handling an exception, it would be quite handy to be able to catch the original exception. This is simply not possible today, and so it is not possible to offer this in a way which works on earlier versions of base. I'd be quite concerned if this didn't offer some additional power that wasn't available before. Isn't that the point of changing things / adding such features? -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Tue Apr 21 21:59:29 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 14:59:29 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Ah, but it looks like Niklas does have a patch which adds implicit locations to such functions: https://phabricator.haskell.org/D861 However, there are some issues with changing the API of these functions: https://phabricator.haskell.org/D861#23250 (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" thread) On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan wrote: > Hmm, that patch doesn't appear to add stack traces to 'Prelude.error', > which is what Carter wants here. Also, I think it would be done with > profiling callstacks rather than implicit callstacks. But it's certainly > also useful to have functions which do the same with implicit callstacks! > > > On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge wrote: > >> Maybe I'm missing something, but isn't this already implemented? >> >> https://phabricator.haskell.org/D578 >> >> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan wrote: >> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >> > wrote: >> >> >> >> if you can patch prelude error to include stack traces, i will owe you >> a >> >> >=1 beer each at the next two icfps. Thats all i want for christmas. :) >> > >> > >> > Sounds good! No promises, but I'll be giving this a try soon. Looking >> > forward to ICFP beers either way :D >> > >> >> i can't speak for how a different patch might work out, because thats >> not >> >> what I'd tried at the time. If you have a go, please share the results! >> >> -Carter >> >> >> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >> wrote: >> >>> >> >>> Hi Carter! >> >>> >> >>> Interesting! This thread, right? >> >>> >> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >> >>> >> >>> I haven't tried this as a patch to base, but I'm certain that the >> core of >> >>> the proposal has no extra dependencies. Note that the proposal isn't >> about >> >>> stack traces in particular - that's just one application of being >> able to >> >>> throw exceptions with extra information. >> >>> >> >>> Even if `throwTo` isn't modified to throw exceptions with stack >> traces, >> >>> this functionality could be provided outside of `Control.Exception` >> (though, >> >>> that does seem like the right place to put it). I'm surprised that >> the >> >>> circularity was so problematic, though. Why isn't it sufficient to >> have an >> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >> >>> >> >>> -Michael >> >>> >> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >> >>> wrote: >> >>>> >> >>>> Hey Michael, >> >>>> I actually proposed something along these lines that got OK'd by >> >>>> libraries early this past fall, the main challenge we hit was >> actually doing >> >>>> the enginering to add the stack traces to exceptions! theres some >> nasty >> >>>> module cycles in base that happen when you try to weave things >> around so >> >>>> that the standard error "message here" call includes some stack >> trace info. >> >>>> Have you tried to do that simple starter patch to base? >> >>>> >> >>>> Chris Allen and I spent like 2 days trying to get it to work and just >> >>>> gave up because of the cycles. We (and others) would probably love >> some >> >>>> headway on that front. >> >>>> >> >>>> Theres also some in progress work to use the dwarf debugging info >> data >> >>>> in >7.10 to provide useful stack traces in the default builds for >> GHC afaik, >> >>>> 'cause the stack trace functionality you're pointing at currenlty >> only work >> >>>> on profiled builds >> >>>> >> >>>> cheers >> >>>> -Carter >> >>>> >> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >> >>>> wrote: >> >>>>> >> >>>>> Control.Exception currently lacks a good way to supply extra >> >>>>> information along with exceptions. For example, exceptions could be >> >>>>> thrown along with their callstack[1] or implicit stack[2], but we >> have >> >>>>> no generic way to include this information with exceptions. >> >>>>> >> >>>>> Proposed Solution >> >>>>> ================= >> >>>>> >> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` to the >> >>>>> `SomeException` datatype. This list stores additional information >> >>>>> about the exception. These `ExceptionInfo` instances use a >> mechanism >> >>>>> which is pretty much identical to the dynamic way the `Exception` >> type >> >>>>> works: >> >>>>> >> >>>>> data SomeException = forall e . Exception e => >> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >> >>>>> >> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >> >>>>> SomeExceptionInfo a >> >>>>> >> >>>>> class Typeable a => ExceptionInfo a where >> >>>>> displayExceptionInfo :: a -> String >> >>>>> >> >>>>> addExceptionInfo >> >>>>> :: (ExceptionInfo a, Exception e) >> >>>>> => a -> e -> SomeException >> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) = >> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >> >>>>> >> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` has, >> >>>>> because I don't see much point in supporting a hierarchy for >> exception >> >>>>> info. The `Typeable` superclass constraint supplies the necessary >> >>>>> casting. >> >>>>> >> >>>>> `SomeExceptionInfo` could validly instead just use the constraint >> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a new >> >>>>> class for this so that: >> >>>>> >> >>>>> * The user can specify a custom `displayExceptionInfo` >> >>>>> implementation, for when this extra info is presented to the user. >> >>>>> This function would be invoked by the `show` implementation for >> >>>>> `SomeException`. >> >>>>> >> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >> >>>>> Similarly to exceptions, I imagine that a type with a >> >>>>> `ExceptionInfo` instance won't be used for anything but acting as >> >>>>> such an annotation. Having a class for this allows you to ask >> GHCI >> >>>>> about all in-scope exception info types via `:info ExceptionInfo`. >> >>>>> >> >>>>> Backwards Compatibility >> >>>>> ======================= >> >>>>> >> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This >> means >> >>>>> that this change could be made without breaking code: >> >>>>> >> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >> >>>>> SomeException x = SomeExceptionWithInfo x [] >> >>>>> >> >>>>> Note that consumers of this do not need to enable >> `-XPatternSynonyms`. >> >>>>> >> >>>>> Applications >> >>>>> ============ >> >>>>> >> >>>>> Callstacks >> >>>>> ---------- >> >>>>> >> >>>>> As mentioned at the beginning, this can be used to add callstacks to >> >>>>> exceptions: >> >>>>> >> >>>>> newtype ExceptionCallStack = >> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >> >>>>> deriving Typeable >> >>>>> >> >>>>> instance ExceptionInfo ExceptionCallStack where >> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >> >>>>> >> >>>>> throwIOWithStack :: Exception e => e -> IO a >> >>>>> throwIOWithStack e = do >> >>>>> stack <- currentCallStack >> >>>>> if null stack >> >>>>> then throwIO e >> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >> stack) >> >>>>> e) >> >>>>> >> >>>>> I see little downside for making something like this the default >> >>>>> implementation `throwIO`. Each rethrowing of the `SomeException` >> >>>>> would add an additional stacktrace to its annotation, much like the >> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >> >>>>> stacktraces would be associated with the exception, rather than just >> >>>>> listing locations that exceptions were thrown. This makes it >> >>>>> tractable to debug exceptions that occur in concurrent programs, or >> in >> >>>>> programs which frequently throw exceptions during normal >> functioning. >> >>>>> >> >>>>> Throwing Exceptions in Handlers >> >>>>> ------------------------------- >> >>>>> >> >>>>> Example: >> >>>>> >> >>>>> main = >> >>>>> throwIO InformativeErrorMessage `finally` >> >>>>> throwIO ObscureCleanupIssue >> >>>>> >> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't see it, >> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >> >>>>> issues: >> >>>>> >> >>>>> 1. If the exception is handled by the default handler and yielded to >> >>>>> the user, then the more informative error is lost. >> >>>>> >> >>>>> 2. Callers who expect to catch the "Informative error message" won't >> >>>>> run their handlers for this exception type. >> >>>>> >> >>>>> Problem 1 can now easily be resolved by adding some info to the >> >>>>> exception: >> >>>>> >> >>>>> data ExceptionCause = ExceptionCause >> >>>>> { unExceptionCause :: SomeException } >> >>>>> deriving Typeable >> >>>>> >> >>>>> instance ExceptionInfo ExceptionCause where >> >>>>> displayExceptionInfo fe = >> >>>>> "thrown while handling " ++ >> >>>>> displayException (unExceptionCause fe) >> >>>>> >> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >> >>>>> catch f g = f `oldCatch` handler >> >>>>> where >> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >> >>>>> throwIO (addExceptionInfo info ex') >> >>>>> where >> >>>>> info = ExceptionCause (toException ex) >> >>>>> >> >>>>> This implementation of `catch` is written in a backwards-compatible >> >>>>> way, such that the exception thrown during finalization is still the >> >>>>> one that gets rethrown. The "original" exception is recorded in the >> >>>>> added info. This is the same approach used by Python 3's >> >>>>> `__context__` attribute[3]. This was brought to my attention in a >> >>>>> post by Mike Meyer[4], in a thread about having bracket not suppress >> >>>>> the original exception[5]. >> >>>>> >> >>>>> This doesn't directly resolve issue #2, due to this backwards >> >>>>> compatibility. With the earlier example, a `catch` handler for >> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >> >>>>> exception being rethrown. This can be resolved by having a variant >> of >> >>>>> catch which instead throws the original exception. This might be a >> >>>>> good default for finalization handlers like `bracket` and `finally`. >> >>>>> >> >>>>> Asynchronous Exceptions >> >>>>> ----------------------- >> >>>>> >> >>>>> Currently, the only reliable way to catch exceptions, ignoring async >> >>>>> exceptions, is to fork a new thread. This is the approach used by >> the >> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that we >> need >> >>>>> to go to such lengths due to the lack of one bit of information >> about >> >>>>> the exception! This would resolve ghc trac #5902[7]. >> >>>>> >> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >> enforce >> >>>>> anything. Any exception can be thrown as a sync or async exception. >> >>>>> Instead, we ought to have a reliable way to know if an exception is >> >>>>> synchronous or asynchronous. Here's what this would look like: >> >>>>> >> >>>>> data IsAsync = IsAsync >> >>>>> deriving (Typeable, Show) >> >>>>> >> >>>>> instance ExceptionInfo IsAsync where >> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >> >>>>> >> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >> >>>>> >> >>>>> The details of this get a bit tricky: What happens if `throwIO` is >> >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag set? >> >>>>> I'm going to leave out my thoughts on this for now as the >> interactions >> >>>>> between unsafePerformIO and the concept of "rethrowing" async >> >>>>> exceptions. Such details are explained in a post by Edsko de >> Vries[8] >> >>>>> and ghc trac #2558[9]. >> >>>>> >> >>>>> Issue: fromException loses info >> >>>>> =============================== >> >>>>> >> >>>>> I can think of one main non-ideal aspect of this proposal: >> >>>>> >> >>>>> Currently, the `toException` and `fromException` methods usually >> form >> >>>>> a prism. In other words, when `fromException` yields a `Just`, you >> >>>>> should get the same `SomeException` when using `toException` on that >> >>>>> value. >> >>>>> >> >>>>> For example, >> >>>>> >> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO >> ex >> >>>>> >> >>>>> is equivalent to >> >>>>> >> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >> >>>>> >> >>>>> However, with exception info added to just `SomeException`, and no >> >>>>> changes to existing `Exception` instances, this >> >>>>> doesn't hold. Exceptions caught as a specific exception type get >> >>>>> rethrown with less information. >> >>>>> >> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a field >> >>>>> to existing `Exception` instances. This would require the use of >> >>>>> non-default implementations of the `toException` and `fromException` >> >>>>> instances. >> >>>>> >> >>>>> Another approach is to have variants of `catch` and `throw` which >> also >> >>>>> pass around the `[SomeExceptionInfo]`. >> >>>>> >> >>>>> [1] >> >>>>> >> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >> >>>>> [2] >> >>>>> >> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >> >>>>> [4] >> >>>>> >> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >> >>>>> [5] >> >>>>> >> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >> >>>>> >> >>>>> _______________________________________________ >> >>>>> Libraries mailing list >> >>>>> Libraries at haskell.org >> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >>>>> >> >>>> >> >>> >> >> >> > >> > >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Tue Apr 21 22:06:17 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Tue, 21 Apr 2015 18:06:17 -0400 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On a more important note: assuming ghc 7.12 has support for informative stack traces via dwarf by default, wouldn't that eliminate the need for this proposal? Namely : there perhaps should be some reasonable way to talk about concatting stack traces perhaps? Phrased differently: how is the info that should perhaps be in informative stack traces not subsuming the info of this proposal? On Tuesday, April 21, 2015, Michael Sloan wrote: > Ah, but it looks like Niklas does have a patch which adds implicit > locations to such functions: https://phabricator.haskell.org/D861 > > However, there are some issues with changing the API of these functions: > https://phabricator.haskell.org/D861#23250 > > (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" thread) > > On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan > wrote: > >> Hmm, that patch doesn't appear to add stack traces to 'Prelude.error', >> which is what Carter wants here. Also, I think it would be done with >> profiling callstacks rather than implicit callstacks. But it's certainly >> also useful to have functions which do the same with implicit callstacks! >> >> >> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge > > wrote: >> >>> Maybe I'm missing something, but isn't this already implemented? >>> >>> https://phabricator.haskell.org/D578 >>> >>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >> > wrote: >>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>> > >> > wrote: >>> >> >>> >> if you can patch prelude error to include stack traces, i will owe >>> you a >>> >> >=1 beer each at the next two icfps. Thats all i want for christmas. >>> :) >>> > >>> > >>> > Sounds good! No promises, but I'll be giving this a try soon. Looking >>> > forward to ICFP beers either way :D >>> > >>> >> i can't speak for how a different patch might work out, because thats >>> not >>> >> what I'd tried at the time. If you have a go, please share the >>> results! >>> >> -Carter >>> >> >>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >> > wrote: >>> >>> >>> >>> Hi Carter! >>> >>> >>> >>> Interesting! This thread, right? >>> >>> >>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>> >>> >>> >>> I haven't tried this as a patch to base, but I'm certain that the >>> core of >>> >>> the proposal has no extra dependencies. Note that the proposal >>> isn't about >>> >>> stack traces in particular - that's just one application of being >>> able to >>> >>> throw exceptions with extra information. >>> >>> >>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>> traces, >>> >>> this functionality could be provided outside of `Control.Exception` >>> (though, >>> >>> that does seem like the right place to put it). I'm surprised that >>> the >>> >>> circularity was so problematic, though. Why isn't it sufficient to >>> have an >>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>> >>> >>> >>> -Michael >>> >>> >>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>> >>> >> > wrote: >>> >>>> >>> >>>> Hey Michael, >>> >>>> I actually proposed something along these lines that got OK'd by >>> >>>> libraries early this past fall, the main challenge we hit was >>> actually doing >>> >>>> the enginering to add the stack traces to exceptions! theres some >>> nasty >>> >>>> module cycles in base that happen when you try to weave things >>> around so >>> >>>> that the standard error "message here" call includes some stack >>> trace info. >>> >>>> Have you tried to do that simple starter patch to base? >>> >>>> >>> >>>> Chris Allen and I spent like 2 days trying to get it to work and >>> just >>> >>>> gave up because of the cycles. We (and others) would probably love >>> some >>> >>>> headway on that front. >>> >>>> >>> >>>> Theres also some in progress work to use the dwarf debugging info >>> data >>> >>>> in >7.10 to provide useful stack traces in the default builds for >>> GHC afaik, >>> >>>> 'cause the stack trace functionality you're pointing at currenlty >>> only work >>> >>>> on profiled builds >>> >>>> >>> >>>> cheers >>> >>>> -Carter >>> >>>> >>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >> > >>> >>>> wrote: >>> >>>>> >>> >>>>> Control.Exception currently lacks a good way to supply extra >>> >>>>> information along with exceptions. For example, exceptions could >>> be >>> >>>>> thrown along with their callstack[1] or implicit stack[2], but we >>> have >>> >>>>> no generic way to include this information with exceptions. >>> >>>>> >>> >>>>> Proposed Solution >>> >>>>> ================= >>> >>>>> >>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` to >>> the >>> >>>>> `SomeException` datatype. This list stores additional information >>> >>>>> about the exception. These `ExceptionInfo` instances use a >>> mechanism >>> >>>>> which is pretty much identical to the dynamic way the `Exception` >>> type >>> >>>>> works: >>> >>>>> >>> >>>>> data SomeException = forall e . Exception e => >>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>> >>>>> >>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>> >>>>> SomeExceptionInfo a >>> >>>>> >>> >>>>> class Typeable a => ExceptionInfo a where >>> >>>>> displayExceptionInfo :: a -> String >>> >>>>> >>> >>>>> addExceptionInfo >>> >>>>> :: (ExceptionInfo a, Exception e) >>> >>>>> => a -> e -> SomeException >>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e xs) >>> = >>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>> >>>>> >>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` has, >>> >>>>> because I don't see much point in supporting a hierarchy for >>> exception >>> >>>>> info. The `Typeable` superclass constraint supplies the necessary >>> >>>>> casting. >>> >>>>> >>> >>>>> `SomeExceptionInfo` could validly instead just use the constraint >>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a new >>> >>>>> class for this so that: >>> >>>>> >>> >>>>> * The user can specify a custom `displayExceptionInfo` >>> >>>>> implementation, for when this extra info is presented to the >>> user. >>> >>>>> This function would be invoked by the `show` implementation for >>> >>>>> `SomeException`. >>> >>>>> >>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>> >>>>> Similarly to exceptions, I imagine that a type with a >>> >>>>> `ExceptionInfo` instance won't be used for anything but acting as >>> >>>>> such an annotation. Having a class for this allows you to ask >>> GHCI >>> >>>>> about all in-scope exception info types via `:info >>> ExceptionInfo`. >>> >>>>> >>> >>>>> Backwards Compatibility >>> >>>>> ======================= >>> >>>>> >>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This >>> means >>> >>>>> that this change could be made without breaking code: >>> >>>>> >>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>> >>>>> >>> >>>>> Note that consumers of this do not need to enable >>> `-XPatternSynonyms`. >>> >>>>> >>> >>>>> Applications >>> >>>>> ============ >>> >>>>> >>> >>>>> Callstacks >>> >>>>> ---------- >>> >>>>> >>> >>>>> As mentioned at the beginning, this can be used to add callstacks >>> to >>> >>>>> exceptions: >>> >>>>> >>> >>>>> newtype ExceptionCallStack = >>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>> >>>>> deriving Typeable >>> >>>>> >>> >>>>> instance ExceptionInfo ExceptionCallStack where >>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>> >>>>> >>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>> >>>>> throwIOWithStack e = do >>> >>>>> stack <- currentCallStack >>> >>>>> if null stack >>> >>>>> then throwIO e >>> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >>> stack) >>> >>>>> e) >>> >>>>> >>> >>>>> I see little downside for making something like this the default >>> >>>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>> >>>>> would add an additional stacktrace to its annotation, much like the >>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>> >>>>> stacktraces would be associated with the exception, rather than >>> just >>> >>>>> listing locations that exceptions were thrown. This makes it >>> >>>>> tractable to debug exceptions that occur in concurrent programs, >>> or in >>> >>>>> programs which frequently throw exceptions during normal >>> functioning. >>> >>>>> >>> >>>>> Throwing Exceptions in Handlers >>> >>>>> ------------------------------- >>> >>>>> >>> >>>>> Example: >>> >>>>> >>> >>>>> main = >>> >>>>> throwIO InformativeErrorMessage `finally` >>> >>>>> throwIO ObscureCleanupIssue >>> >>>>> >>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't see >>> it, >>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>> >>>>> issues: >>> >>>>> >>> >>>>> 1. If the exception is handled by the default handler and yielded >>> to >>> >>>>> the user, then the more informative error is lost. >>> >>>>> >>> >>>>> 2. Callers who expect to catch the "Informative error message" >>> won't >>> >>>>> run their handlers for this exception type. >>> >>>>> >>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>> >>>>> exception: >>> >>>>> >>> >>>>> data ExceptionCause = ExceptionCause >>> >>>>> { unExceptionCause :: SomeException } >>> >>>>> deriving Typeable >>> >>>>> >>> >>>>> instance ExceptionInfo ExceptionCause where >>> >>>>> displayExceptionInfo fe = >>> >>>>> "thrown while handling " ++ >>> >>>>> displayException (unExceptionCause fe) >>> >>>>> >>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>> >>>>> catch f g = f `oldCatch` handler >>> >>>>> where >>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>> >>>>> throwIO (addExceptionInfo info ex') >>> >>>>> where >>> >>>>> info = ExceptionCause (toException ex) >>> >>>>> >>> >>>>> This implementation of `catch` is written in a backwards-compatible >>> >>>>> way, such that the exception thrown during finalization is still >>> the >>> >>>>> one that gets rethrown. The "original" exception is recorded in >>> the >>> >>>>> added info. This is the same approach used by Python 3's >>> >>>>> `__context__` attribute[3]. This was brought to my attention in a >>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>> suppress >>> >>>>> the original exception[5]. >>> >>>>> >>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>> >>>>> compatibility. With the earlier example, a `catch` handler for >>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>> >>>>> exception being rethrown. This can be resolved by having a >>> variant of >>> >>>>> catch which instead throws the original exception. This might be a >>> >>>>> good default for finalization handlers like `bracket` and >>> `finally`. >>> >>>>> >>> >>>>> Asynchronous Exceptions >>> >>>>> ----------------------- >>> >>>>> >>> >>>>> Currently, the only reliable way to catch exceptions, ignoring >>> async >>> >>>>> exceptions, is to fork a new thread. This is the approach used by >>> the >>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that we >>> need >>> >>>>> to go to such lengths due to the lack of one bit of information >>> about >>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>> >>>>> >>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >>> enforce >>> >>>>> anything. Any exception can be thrown as a sync or async >>> exception. >>> >>>>> Instead, we ought to have a reliable way to know if an exception is >>> >>>>> synchronous or asynchronous. Here's what this would look like: >>> >>>>> >>> >>>>> data IsAsync = IsAsync >>> >>>>> deriving (Typeable, Show) >>> >>>>> >>> >>>>> instance ExceptionInfo IsAsync where >>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>> >>>>> >>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>> >>>>> >>> >>>>> The details of this get a bit tricky: What happens if `throwIO` is >>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag >>> set? >>> >>>>> I'm going to leave out my thoughts on this for now as the >>> interactions >>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>> >>>>> exceptions. Such details are explained in a post by Edsko de >>> Vries[8] >>> >>>>> and ghc trac #2558[9]. >>> >>>>> >>> >>>>> Issue: fromException loses info >>> >>>>> =============================== >>> >>>>> >>> >>>>> I can think of one main non-ideal aspect of this proposal: >>> >>>>> >>> >>>>> Currently, the `toException` and `fromException` methods usually >>> form >>> >>>>> a prism. In other words, when `fromException` yields a `Just`, you >>> >>>>> should get the same `SomeException` when using `toException` on >>> that >>> >>>>> value. >>> >>>>> >>> >>>>> For example, >>> >>>>> >>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> throwIO >>> ex >>> >>>>> >>> >>>>> is equivalent to >>> >>>>> >>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>> >>>>> >>> >>>>> However, with exception info added to just `SomeException`, and no >>> >>>>> changes to existing `Exception` instances, this >>> >>>>> doesn't hold. Exceptions caught as a specific exception type get >>> >>>>> rethrown with less information. >>> >>>>> >>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a >>> field >>> >>>>> to existing `Exception` instances. This would require the use of >>> >>>>> non-default implementations of the `toException` and >>> `fromException` >>> >>>>> instances. >>> >>>>> >>> >>>>> Another approach is to have variants of `catch` and `throw` which >>> also >>> >>>>> pass around the `[SomeExceptionInfo]`. >>> >>>>> >>> >>>>> [1] >>> >>>>> >>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>> >>>>> [2] >>> >>>>> >>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>> >>>>> [4] >>> >>>>> >>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>> >>>>> [5] >>> >>>>> >>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>> >>>>> >>> >>>>> _______________________________________________ >>> >>>>> Libraries mailing list >>> >>>>> Libraries at haskell.org >>> >>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>>>> >>> >>>> >>> >>> >>> >> >>> > >>> > >>> > _______________________________________________ >>> > Libraries mailing list >>> > Libraries at haskell.org >>> >>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> > >>> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Tue Apr 21 22:24:01 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 15:24:01 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: No, this proposal is not specifically about stack traces, that is just one of the usecases. Instead, this is about a general mechanism for including extra information with exceptions. The core of this proposal is still relevant even if the behavior of error / throw / throwTo / etc remain unchanged. I'm not familiar with how the new dwarf stuff will interact with throwing / displaying exceptions. It seems like this would require having the debugger break at the throw site, and exceptions would still lack stack traces. Having informative stack traces is quite orthogonal to having a good place to store them. Note that in my original proposal text I mentioned that this is agnostic of the particular source of the stack trace. In particular, this could be used with a profiling stack trace, implicit callstack, or, indeed, these traces via dwarf. -Michael On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > On a more important note: assuming ghc 7.12 has support for informative > stack traces via dwarf by default, wouldn't that eliminate the need for > this proposal? Namely : there perhaps should be some reasonable way to talk > about concatting stack traces perhaps? > > Phrased differently: how is the info that should perhaps be in informative > stack traces not subsuming the info of this proposal? > > > On Tuesday, April 21, 2015, Michael Sloan wrote: > >> Ah, but it looks like Niklas does have a patch which adds implicit >> locations to such functions: https://phabricator.haskell.org/D861 >> >> However, there are some issues with changing the API of these functions: >> https://phabricator.haskell.org/D861#23250 >> >> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" thread) >> >> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan wrote: >> >>> Hmm, that patch doesn't appear to add stack traces to 'Prelude.error', >>> which is what Carter wants here. Also, I think it would be done with >>> profiling callstacks rather than implicit callstacks. But it's certainly >>> also useful to have functions which do the same with implicit callstacks! >>> >>> >>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge wrote: >>> >>>> Maybe I'm missing something, but isn't this already implemented? >>>> >>>> https://phabricator.haskell.org/D578 >>>> >>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>> wrote: >>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>> > wrote: >>>> >> >>>> >> if you can patch prelude error to include stack traces, i will owe >>>> you a >>>> >> >=1 beer each at the next two icfps. Thats all i want for christmas. >>>> :) >>>> > >>>> > >>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>> Looking >>>> > forward to ICFP beers either way :D >>>> > >>>> >> i can't speak for how a different patch might work out, because >>>> thats not >>>> >> what I'd tried at the time. If you have a go, please share the >>>> results! >>>> >> -Carter >>>> >> >>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >>>> wrote: >>>> >>> >>>> >>> Hi Carter! >>>> >>> >>>> >>> Interesting! This thread, right? >>>> >>> >>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>> >>> >>>> >>> I haven't tried this as a patch to base, but I'm certain that the >>>> core of >>>> >>> the proposal has no extra dependencies. Note that the proposal >>>> isn't about >>>> >>> stack traces in particular - that's just one application of being >>>> able to >>>> >>> throw exceptions with extra information. >>>> >>> >>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>> traces, >>>> >>> this functionality could be provided outside of `Control.Exception` >>>> (though, >>>> >>> that does seem like the right place to put it). I'm surprised that >>>> the >>>> >>> circularity was so problematic, though. Why isn't it sufficient to >>>> have an >>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>> >>> >>>> >>> -Michael >>>> >>> >>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>> >>> wrote: >>>> >>>> >>>> >>>> Hey Michael, >>>> >>>> I actually proposed something along these lines that got OK'd by >>>> >>>> libraries early this past fall, the main challenge we hit was >>>> actually doing >>>> >>>> the enginering to add the stack traces to exceptions! theres some >>>> nasty >>>> >>>> module cycles in base that happen when you try to weave things >>>> around so >>>> >>>> that the standard error "message here" call includes some stack >>>> trace info. >>>> >>>> Have you tried to do that simple starter patch to base? >>>> >>>> >>>> >>>> Chris Allen and I spent like 2 days trying to get it to work and >>>> just >>>> >>>> gave up because of the cycles. We (and others) would probably love >>>> some >>>> >>>> headway on that front. >>>> >>>> >>>> >>>> Theres also some in progress work to use the dwarf debugging info >>>> data >>>> >>>> in >7.10 to provide useful stack traces in the default builds for >>>> GHC afaik, >>>> >>>> 'cause the stack trace functionality you're pointing at currenlty >>>> only work >>>> >>>> on profiled builds >>>> >>>> >>>> >>>> cheers >>>> >>>> -Carter >>>> >>>> >>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >>>> >>>> wrote: >>>> >>>>> >>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>> >>>>> information along with exceptions. For example, exceptions could >>>> be >>>> >>>>> thrown along with their callstack[1] or implicit stack[2], but we >>>> have >>>> >>>>> no generic way to include this information with exceptions. >>>> >>>>> >>>> >>>>> Proposed Solution >>>> >>>>> ================= >>>> >>>>> >>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` to >>>> the >>>> >>>>> `SomeException` datatype. This list stores additional information >>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>> mechanism >>>> >>>>> which is pretty much identical to the dynamic way the `Exception` >>>> type >>>> >>>>> works: >>>> >>>>> >>>> >>>>> data SomeException = forall e . Exception e => >>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>> >>>>> >>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>> >>>>> SomeExceptionInfo a >>>> >>>>> >>>> >>>>> class Typeable a => ExceptionInfo a where >>>> >>>>> displayExceptionInfo :: a -> String >>>> >>>>> >>>> >>>>> addExceptionInfo >>>> >>>>> :: (ExceptionInfo a, Exception e) >>>> >>>>> => a -> e -> SomeException >>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e >>>> xs) = >>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>> >>>>> >>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` >>>> has, >>>> >>>>> because I don't see much point in supporting a hierarchy for >>>> exception >>>> >>>>> info. The `Typeable` superclass constraint supplies the necessary >>>> >>>>> casting. >>>> >>>>> >>>> >>>>> `SomeExceptionInfo` could validly instead just use the constraint >>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a >>>> new >>>> >>>>> class for this so that: >>>> >>>>> >>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>> >>>>> implementation, for when this extra info is presented to the >>>> user. >>>> >>>>> This function would be invoked by the `show` implementation for >>>> >>>>> `SomeException`. >>>> >>>>> >>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>> >>>>> `ExceptionInfo` instance won't be used for anything but acting >>>> as >>>> >>>>> such an annotation. Having a class for this allows you to ask >>>> GHCI >>>> >>>>> about all in-scope exception info types via `:info >>>> ExceptionInfo`. >>>> >>>>> >>>> >>>>> Backwards Compatibility >>>> >>>>> ======================= >>>> >>>>> >>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This >>>> means >>>> >>>>> that this change could be made without breaking code: >>>> >>>>> >>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>> >>>>> >>>> >>>>> Note that consumers of this do not need to enable >>>> `-XPatternSynonyms`. >>>> >>>>> >>>> >>>>> Applications >>>> >>>>> ============ >>>> >>>>> >>>> >>>>> Callstacks >>>> >>>>> ---------- >>>> >>>>> >>>> >>>>> As mentioned at the beginning, this can be used to add callstacks >>>> to >>>> >>>>> exceptions: >>>> >>>>> >>>> >>>>> newtype ExceptionCallStack = >>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>> >>>>> deriving Typeable >>>> >>>>> >>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>> >>>>> >>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>> >>>>> throwIOWithStack e = do >>>> >>>>> stack <- currentCallStack >>>> >>>>> if null stack >>>> >>>>> then throwIO e >>>> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >>>> stack) >>>> >>>>> e) >>>> >>>>> >>>> >>>>> I see little downside for making something like this the default >>>> >>>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>>> >>>>> would add an additional stacktrace to its annotation, much like >>>> the >>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>> >>>>> stacktraces would be associated with the exception, rather than >>>> just >>>> >>>>> listing locations that exceptions were thrown. This makes it >>>> >>>>> tractable to debug exceptions that occur in concurrent programs, >>>> or in >>>> >>>>> programs which frequently throw exceptions during normal >>>> functioning. >>>> >>>>> >>>> >>>>> Throwing Exceptions in Handlers >>>> >>>>> ------------------------------- >>>> >>>>> >>>> >>>>> Example: >>>> >>>>> >>>> >>>>> main = >>>> >>>>> throwIO InformativeErrorMessage `finally` >>>> >>>>> throwIO ObscureCleanupIssue >>>> >>>>> >>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't see >>>> it, >>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>>> >>>>> issues: >>>> >>>>> >>>> >>>>> 1. If the exception is handled by the default handler and yielded >>>> to >>>> >>>>> the user, then the more informative error is lost. >>>> >>>>> >>>> >>>>> 2. Callers who expect to catch the "Informative error message" >>>> won't >>>> >>>>> run their handlers for this exception type. >>>> >>>>> >>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>> >>>>> exception: >>>> >>>>> >>>> >>>>> data ExceptionCause = ExceptionCause >>>> >>>>> { unExceptionCause :: SomeException } >>>> >>>>> deriving Typeable >>>> >>>>> >>>> >>>>> instance ExceptionInfo ExceptionCause where >>>> >>>>> displayExceptionInfo fe = >>>> >>>>> "thrown while handling " ++ >>>> >>>>> displayException (unExceptionCause fe) >>>> >>>>> >>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>> >>>>> catch f g = f `oldCatch` handler >>>> >>>>> where >>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>> >>>>> throwIO (addExceptionInfo info ex') >>>> >>>>> where >>>> >>>>> info = ExceptionCause (toException ex) >>>> >>>>> >>>> >>>>> This implementation of `catch` is written in a >>>> backwards-compatible >>>> >>>>> way, such that the exception thrown during finalization is still >>>> the >>>> >>>>> one that gets rethrown. The "original" exception is recorded in >>>> the >>>> >>>>> added info. This is the same approach used by Python 3's >>>> >>>>> `__context__` attribute[3]. This was brought to my attention in a >>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>> suppress >>>> >>>>> the original exception[5]. >>>> >>>>> >>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>> >>>>> compatibility. With the earlier example, a `catch` handler for >>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>> >>>>> exception being rethrown. This can be resolved by having a >>>> variant of >>>> >>>>> catch which instead throws the original exception. This might be >>>> a >>>> >>>>> good default for finalization handlers like `bracket` and >>>> `finally`. >>>> >>>>> >>>> >>>>> Asynchronous Exceptions >>>> >>>>> ----------------------- >>>> >>>>> >>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring >>>> async >>>> >>>>> exceptions, is to fork a new thread. This is the approach used >>>> by the >>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that we >>>> need >>>> >>>>> to go to such lengths due to the lack of one bit of information >>>> about >>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>> >>>>> >>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >>>> enforce >>>> >>>>> anything. Any exception can be thrown as a sync or async >>>> exception. >>>> >>>>> Instead, we ought to have a reliable way to know if an exception >>>> is >>>> >>>>> synchronous or asynchronous. Here's what this would look like: >>>> >>>>> >>>> >>>>> data IsAsync = IsAsync >>>> >>>>> deriving (Typeable, Show) >>>> >>>>> >>>> >>>>> instance ExceptionInfo IsAsync where >>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>> >>>>> >>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>> >>>>> >>>> >>>>> The details of this get a bit tricky: What happens if `throwIO` is >>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag >>>> set? >>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>> interactions >>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>> Vries[8] >>>> >>>>> and ghc trac #2558[9]. >>>> >>>>> >>>> >>>>> Issue: fromException loses info >>>> >>>>> =============================== >>>> >>>>> >>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>> >>>>> >>>> >>>>> Currently, the `toException` and `fromException` methods usually >>>> form >>>> >>>>> a prism. In other words, when `fromException` yields a `Just`, >>>> you >>>> >>>>> should get the same `SomeException` when using `toException` on >>>> that >>>> >>>>> value. >>>> >>>>> >>>> >>>>> For example, >>>> >>>>> >>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>> throwIO ex >>>> >>>>> >>>> >>>>> is equivalent to >>>> >>>>> >>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>> >>>>> >>>> >>>>> However, with exception info added to just `SomeException`, and no >>>> >>>>> changes to existing `Exception` instances, this >>>> >>>>> doesn't hold. Exceptions caught as a specific exception type get >>>> >>>>> rethrown with less information. >>>> >>>>> >>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a >>>> field >>>> >>>>> to existing `Exception` instances. This would require the use of >>>> >>>>> non-default implementations of the `toException` and >>>> `fromException` >>>> >>>>> instances. >>>> >>>>> >>>> >>>>> Another approach is to have variants of `catch` and `throw` which >>>> also >>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>> >>>>> >>>> >>>>> [1] >>>> >>>>> >>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>> >>>>> [2] >>>> >>>>> >>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>> >>>>> [4] >>>> >>>>> >>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>> >>>>> [5] >>>> >>>>> >>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>> >>>>> >>>> >>>>> _______________________________________________ >>>> >>>>> Libraries mailing list >>>> >>>>> Libraries at haskell.org >>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>>> >>>> >>>> >>>> >>> >>>> >> >>>> > >>>> > >>>> > _______________________________________________ >>>> > Libraries mailing list >>>> > Libraries at haskell.org >>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> > >>>> >>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From davean at xkcd.com Wed Apr 22 01:40:34 2015 From: davean at xkcd.com (davean) Date: Tue, 21 Apr 2015 21:40:34 -0400 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: So, I've had a number of issues with exceptions. This has been one of them. I don't really like this proposal as it stands though as it seems to make catch a specific exception with said extra info more difficult. This is data Control.Exception can move around on its own though, right? The problem really isn't passing it internal, we could just make a (Stack, SomeException) tuple just fine, in theory I think (I'll admit I've not actually reviewed the code, and this isn't meant as a complete proposal but more a thought experiment). The problem is code handling the data and working with old code while not losing any of the power of the current system. So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> IO a If we want access to the new information, but that's not really satisfactory. Real code regularly wants to (picking an arbitrary instance of Exception) do: catch :: IO a -> (IOError -> IO a) -> IO a only we still want new data. Now one could do something like: catch :: IO a -> (Stack -> IOError -> IO a) -> IO a but that is not very upgradable and it breaks existing code. But this is just a matter of requesting information, so one could do something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a where: data WithStack e = WithStack Stack e Or maybe one just addes: catchWithContext :: Exception e => IO a -> (Context -> e -> IO a) -> IO a Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> IO a Now existing code continues to run and we can feed our exception handlers the data they want, even when we want some specific exception instead of just any exception. Now that still leave a hole in what I want out of exceptions. We're still short of programmatic interrogating them, or even telling what the exception was if we didn't expect it! Consider AssertionFailed . Its show instance is "showsPrec _ (AssertionFailed err) = showString err", so if we print out the SomeException, we get whatever string is in AssertionFailed. Which is great if that string makes sense. But you see that on your console and its a bit baffling if it doesn't. It could even be a lie, I can make that say something that looks like its a different exception. We can use the Typeable instance so the program can tell them apart at least though. Which works as long as the exception is single-constructor, or has a well-behaved show instance. What if we come across a monstrosity like http://hackage.haskell.org/package/http-conduit-2.1.5/docs/Network-HTTP-Conduit.html#g:12 and it doesn't have a nice show instance that says which on it is? If Exception added a Data constraint we could actually pull apart these exceptions and start to make proper sense of them reliably. Once you have that there are quite a few useful things you can do with the exceptions you didn't expect. Currently you could only do them by enumerating every possible exception which of course doesn't work for the unexpected. On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan wrote: > No, this proposal is not specifically about stack traces, that is just one > of the usecases. Instead, this is about a general mechanism for including > extra information with exceptions. The core of this proposal is still > relevant even if the behavior of error / throw / throwTo / etc remain > unchanged. > > I'm not familiar with how the new dwarf stuff will interact with throwing > / displaying exceptions. It seems like this would require having the > debugger break at the throw site, and exceptions would still lack stack > traces. Having informative stack traces is quite orthogonal to having a > good place to store them. > > Note that in my original proposal text I mentioned that this is agnostic > of the particular source of the stack trace. In particular, this could be > used with a profiling stack trace, implicit callstack, or, indeed, these > traces via dwarf. > > -Michael > > On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < > carter.schonwald at gmail.com> wrote: > >> On a more important note: assuming ghc 7.12 has support for informative >> stack traces via dwarf by default, wouldn't that eliminate the need for >> this proposal? Namely : there perhaps should be some reasonable way to talk >> about concatting stack traces perhaps? >> >> Phrased differently: how is the info that should perhaps be in >> informative stack traces not subsuming the info of this proposal? >> >> >> On Tuesday, April 21, 2015, Michael Sloan wrote: >> >>> Ah, but it looks like Niklas does have a patch which adds implicit >>> locations to such functions: https://phabricator.haskell.org/D861 >>> >>> However, there are some issues with changing the API of these functions: >>> https://phabricator.haskell.org/D861#23250 >>> >>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" thread) >>> >>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>> wrote: >>> >>>> Hmm, that patch doesn't appear to add stack traces to 'Prelude.error', >>>> which is what Carter wants here. Also, I think it would be done with >>>> profiling callstacks rather than implicit callstacks. But it's certainly >>>> also useful to have functions which do the same with implicit callstacks! >>>> >>>> >>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>> wrote: >>>> >>>>> Maybe I'm missing something, but isn't this already implemented? >>>>> >>>>> https://phabricator.haskell.org/D578 >>>>> >>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>> wrote: >>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>> > wrote: >>>>> >> >>>>> >> if you can patch prelude error to include stack traces, i will owe >>>>> you a >>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>> christmas. :) >>>>> > >>>>> > >>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>> Looking >>>>> > forward to ICFP beers either way :D >>>>> > >>>>> >> i can't speak for how a different patch might work out, because >>>>> thats not >>>>> >> what I'd tried at the time. If you have a go, please share the >>>>> results! >>>>> >> -Carter >>>>> >> >>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >>>>> wrote: >>>>> >>> >>>>> >>> Hi Carter! >>>>> >>> >>>>> >>> Interesting! This thread, right? >>>>> >>> >>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>> >>> >>>>> >>> I haven't tried this as a patch to base, but I'm certain that the >>>>> core of >>>>> >>> the proposal has no extra dependencies. Note that the proposal >>>>> isn't about >>>>> >>> stack traces in particular - that's just one application of being >>>>> able to >>>>> >>> throw exceptions with extra information. >>>>> >>> >>>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>>> traces, >>>>> >>> this functionality could be provided outside of >>>>> `Control.Exception` (though, >>>>> >>> that does seem like the right place to put it). I'm surprised >>>>> that the >>>>> >>> circularity was so problematic, though. Why isn't it sufficient >>>>> to have an >>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>> >>> >>>>> >>> -Michael >>>>> >>> >>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>> >>> wrote: >>>>> >>>> >>>>> >>>> Hey Michael, >>>>> >>>> I actually proposed something along these lines that got OK'd by >>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>> actually doing >>>>> >>>> the enginering to add the stack traces to exceptions! theres some >>>>> nasty >>>>> >>>> module cycles in base that happen when you try to weave things >>>>> around so >>>>> >>>> that the standard error "message here" call includes some stack >>>>> trace info. >>>>> >>>> Have you tried to do that simple starter patch to base? >>>>> >>>> >>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work and >>>>> just >>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>> love some >>>>> >>>> headway on that front. >>>>> >>>> >>>>> >>>> Theres also some in progress work to use the dwarf debugging info >>>>> data >>>>> >>>> in >7.10 to provide useful stack traces in the default builds for >>>>> GHC afaik, >>>>> >>>> 'cause the stack trace functionality you're pointing at currenlty >>>>> only work >>>>> >>>> on profiled builds >>>>> >>>> >>>>> >>>> cheers >>>>> >>>> -Carter >>>>> >>>> >>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >>>> > >>>>> >>>> wrote: >>>>> >>>>> >>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>> >>>>> information along with exceptions. For example, exceptions >>>>> could be >>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], but >>>>> we have >>>>> >>>>> no generic way to include this information with exceptions. >>>>> >>>>> >>>>> >>>>> Proposed Solution >>>>> >>>>> ================= >>>>> >>>>> >>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` to >>>>> the >>>>> >>>>> `SomeException` datatype. This list stores additional >>>>> information >>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>> mechanism >>>>> >>>>> which is pretty much identical to the dynamic way the >>>>> `Exception` type >>>>> >>>>> works: >>>>> >>>>> >>>>> >>>>> data SomeException = forall e . Exception e => >>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>> >>>>> >>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>> >>>>> SomeExceptionInfo a >>>>> >>>>> >>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>> >>>>> displayExceptionInfo :: a -> String >>>>> >>>>> >>>>> >>>>> addExceptionInfo >>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>> >>>>> => a -> e -> SomeException >>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e >>>>> xs) = >>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>> >>>>> >>>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` >>>>> has, >>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>> exception >>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>> necessary >>>>> >>>>> casting. >>>>> >>>>> >>>>> >>>>> `SomeExceptionInfo` could validly instead just use the constraint >>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a >>>>> new >>>>> >>>>> class for this so that: >>>>> >>>>> >>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>> >>>>> implementation, for when this extra info is presented to the >>>>> user. >>>>> >>>>> This function would be invoked by the `show` implementation for >>>>> >>>>> `SomeException`. >>>>> >>>>> >>>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>> >>>>> `ExceptionInfo` instance won't be used for anything but acting >>>>> as >>>>> >>>>> such an annotation. Having a class for this allows you to ask >>>>> GHCI >>>>> >>>>> about all in-scope exception info types via `:info >>>>> ExceptionInfo`. >>>>> >>>>> >>>>> >>>>> Backwards Compatibility >>>>> >>>>> ======================= >>>>> >>>>> >>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This >>>>> means >>>>> >>>>> that this change could be made without breaking code: >>>>> >>>>> >>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>> >>>>> >>>>> >>>>> Note that consumers of this do not need to enable >>>>> `-XPatternSynonyms`. >>>>> >>>>> >>>>> >>>>> Applications >>>>> >>>>> ============ >>>>> >>>>> >>>>> >>>>> Callstacks >>>>> >>>>> ---------- >>>>> >>>>> >>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>> callstacks to >>>>> >>>>> exceptions: >>>>> >>>>> >>>>> >>>>> newtype ExceptionCallStack = >>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>> >>>>> deriving Typeable >>>>> >>>>> >>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>> >>>>> >>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>> >>>>> throwIOWithStack e = do >>>>> >>>>> stack <- currentCallStack >>>>> >>>>> if null stack >>>>> >>>>> then throwIO e >>>>> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >>>>> stack) >>>>> >>>>> e) >>>>> >>>>> >>>>> >>>>> I see little downside for making something like this the default >>>>> >>>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>>>> >>>>> would add an additional stacktrace to its annotation, much like >>>>> the >>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>> >>>>> stacktraces would be associated with the exception, rather than >>>>> just >>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>> >>>>> tractable to debug exceptions that occur in concurrent programs, >>>>> or in >>>>> >>>>> programs which frequently throw exceptions during normal >>>>> functioning. >>>>> >>>>> >>>>> >>>>> Throwing Exceptions in Handlers >>>>> >>>>> ------------------------------- >>>>> >>>>> >>>>> >>>>> Example: >>>>> >>>>> >>>>> >>>>> main = >>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>> >>>>> throwIO ObscureCleanupIssue >>>>> >>>>> >>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't see >>>>> it, >>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>>>> >>>>> issues: >>>>> >>>>> >>>>> >>>>> 1. If the exception is handled by the default handler and >>>>> yielded to >>>>> >>>>> the user, then the more informative error is lost. >>>>> >>>>> >>>>> >>>>> 2. Callers who expect to catch the "Informative error message" >>>>> won't >>>>> >>>>> run their handlers for this exception type. >>>>> >>>>> >>>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>>> >>>>> exception: >>>>> >>>>> >>>>> >>>>> data ExceptionCause = ExceptionCause >>>>> >>>>> { unExceptionCause :: SomeException } >>>>> >>>>> deriving Typeable >>>>> >>>>> >>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>> >>>>> displayExceptionInfo fe = >>>>> >>>>> "thrown while handling " ++ >>>>> >>>>> displayException (unExceptionCause fe) >>>>> >>>>> >>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>> >>>>> catch f g = f `oldCatch` handler >>>>> >>>>> where >>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>> >>>>> where >>>>> >>>>> info = ExceptionCause (toException ex) >>>>> >>>>> >>>>> >>>>> This implementation of `catch` is written in a >>>>> backwards-compatible >>>>> >>>>> way, such that the exception thrown during finalization is still >>>>> the >>>>> >>>>> one that gets rethrown. The "original" exception is recorded in >>>>> the >>>>> >>>>> added info. This is the same approach used by Python 3's >>>>> >>>>> `__context__` attribute[3]. This was brought to my attention in >>>>> a >>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>> suppress >>>>> >>>>> the original exception[5]. >>>>> >>>>> >>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>> >>>>> compatibility. With the earlier example, a `catch` handler for >>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>> variant of >>>>> >>>>> catch which instead throws the original exception. This might >>>>> be a >>>>> >>>>> good default for finalization handlers like `bracket` and >>>>> `finally`. >>>>> >>>>> >>>>> >>>>> Asynchronous Exceptions >>>>> >>>>> ----------------------- >>>>> >>>>> >>>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring >>>>> async >>>>> >>>>> exceptions, is to fork a new thread. This is the approach used >>>>> by the >>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that we >>>>> need >>>>> >>>>> to go to such lengths due to the lack of one bit of information >>>>> about >>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>> >>>>> >>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >>>>> enforce >>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>> exception. >>>>> >>>>> Instead, we ought to have a reliable way to know if an exception >>>>> is >>>>> >>>>> synchronous or asynchronous. Here's what this would look like: >>>>> >>>>> >>>>> >>>>> data IsAsync = IsAsync >>>>> >>>>> deriving (Typeable, Show) >>>>> >>>>> >>>>> >>>>> instance ExceptionInfo IsAsync where >>>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>> >>>>> >>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>> >>>>> >>>>> >>>>> The details of this get a bit tricky: What happens if `throwIO` >>>>> is >>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag >>>>> set? >>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>> interactions >>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>>> Vries[8] >>>>> >>>>> and ghc trac #2558[9]. >>>>> >>>>> >>>>> >>>>> Issue: fromException loses info >>>>> >>>>> =============================== >>>>> >>>>> >>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>> >>>>> >>>>> >>>>> Currently, the `toException` and `fromException` methods usually >>>>> form >>>>> >>>>> a prism. In other words, when `fromException` yields a `Just`, >>>>> you >>>>> >>>>> should get the same `SomeException` when using `toException` on >>>>> that >>>>> >>>>> value. >>>>> >>>>> >>>>> >>>>> For example, >>>>> >>>>> >>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>> throwIO ex >>>>> >>>>> >>>>> >>>>> is equivalent to >>>>> >>>>> >>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>> >>>>> >>>>> >>>>> However, with exception info added to just `SomeException`, and >>>>> no >>>>> >>>>> changes to existing `Exception` instances, this >>>>> >>>>> doesn't hold. Exceptions caught as a specific exception type get >>>>> >>>>> rethrown with less information. >>>>> >>>>> >>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a >>>>> field >>>>> >>>>> to existing `Exception` instances. This would require the use of >>>>> >>>>> non-default implementations of the `toException` and >>>>> `fromException` >>>>> >>>>> instances. >>>>> >>>>> >>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>> which also >>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>> >>>>> >>>>> >>>>> [1] >>>>> >>>>> >>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>> >>>>> [2] >>>>> >>>>> >>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>> >>>>> [4] >>>>> >>>>> >>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>> >>>>> [5] >>>>> >>>>> >>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>> >>>>> >>>>> >>>>> _______________________________________________ >>>>> >>>>> Libraries mailing list >>>>> >>>>> Libraries at haskell.org >>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>>>> >>>> >>>>> >>> >>>>> >> >>>>> > >>>>> > >>>>> > _______________________________________________ >>>>> > Libraries mailing list >>>>> > Libraries at haskell.org >>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> > >>>>> >>>> >>>> >>> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed Apr 22 02:23:38 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Tue, 21 Apr 2015 22:23:38 -0400 Subject: Exceptions with Context Re: Proposal: Add exception info Message-ID: hrm, i like this proposal more, and it seems like with some fleshing out it can be strictly more extensible yet backwards compatible than michael's I'll need to mull it a bit more before I cast my vote, but this seems to sketch out a design that provides the same information, but in a more extensible/backwards compatible fashion (at least in a first cut of thinking about it) (i'm splitting this into a new thread so the discussions dont get mixed up) On Tue, Apr 21, 2015 at 9:40 PM, davean wrote: > So, I've had a number of issues with exceptions. This has been one of > them. I don't really like this proposal as it stands though as it seems to > make catch a specific exception with said extra info more difficult. > > This is data Control.Exception can move around on its own though, right? > The problem really isn't passing it internal, we could just make a (Stack, > SomeException) tuple just fine, in theory I think (I'll admit I've not > actually reviewed the code, and this isn't meant as a complete proposal but > more a thought experiment). The problem is code handling the data and > working with old code while not losing any of the power of the current > system. > > So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a > > Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> IO a > If we want access to the new information, but that's not really > satisfactory. > > Real code regularly wants to (picking an arbitrary instance of Exception) > do: catch :: IO a -> (IOError -> IO a) -> IO a > only we still want new data. > > Now one could do something like: catch :: IO a -> (Stack -> IOError -> IO > a) -> IO a > but that is not very upgradable and it breaks existing code. > > But this is just a matter of requesting information, so one could do > something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a > where: data WithStack e = WithStack Stack e > Or maybe one just addes: catchWithContext :: Exception e => IO a -> > (Context -> e -> IO a) -> IO a > Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> IO a > > Now existing code continues to run and we can feed our exception handlers > the data they want, even when we want some specific exception instead of > just any exception. > > Now that still leave a hole in what I want out of exceptions. We're still > short of programmatic interrogating them, or even telling what the > exception was if we didn't expect it! > > Consider AssertionFailed > . > Its show instance is "showsPrec _ (AssertionFailed err) = showString err", > so if we print out the SomeException, we get whatever string is in > AssertionFailed. Which is great if that string makes sense. But you see > that on your console and its a bit baffling if it doesn't. It could even be > a lie, I can make that say something that looks like its a different > exception. We can use the Typeable instance so the program can tell them > apart at least though. Which works as long as the exception is > single-constructor, or has a well-behaved show instance. What if we come > across a monstrosity like > http://hackage.haskell.org/package/http-conduit-2.1.5/docs/Network-HTTP-Conduit.html#g:12 > and it doesn't have a nice show instance that says which on it is? If > Exception added a Data constraint we could actually pull apart these > exceptions and start to make proper sense of them reliably. > > Once you have that there are quite a few useful things you can do with the > exceptions you didn't expect. Currently you could only do them by > enumerating every possible exception which of course doesn't work for the > unexpected. > > On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan wrote: > >> No, this proposal is not specifically about stack traces, that is just >> one of the usecases. Instead, this is about a general mechanism for >> including extra information with exceptions. The core of this proposal is >> still relevant even if the behavior of error / throw / throwTo / etc remain >> unchanged. >> >> I'm not familiar with how the new dwarf stuff will interact with throwing >> / displaying exceptions. It seems like this would require having the >> debugger break at the throw site, and exceptions would still lack stack >> traces. Having informative stack traces is quite orthogonal to having a >> good place to store them. >> >> Note that in my original proposal text I mentioned that this is agnostic >> of the particular source of the stack trace. In particular, this could be >> used with a profiling stack trace, implicit callstack, or, indeed, these >> traces via dwarf. >> >> -Michael >> >> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> On a more important note: assuming ghc 7.12 has support for informative >>> stack traces via dwarf by default, wouldn't that eliminate the need for >>> this proposal? Namely : there perhaps should be some reasonable way to talk >>> about concatting stack traces perhaps? >>> >>> Phrased differently: how is the info that should perhaps be in >>> informative stack traces not subsuming the info of this proposal? >>> >>> >>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>> >>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>> locations to such functions: https://phabricator.haskell.org/D861 >>>> >>>> However, there are some issues with changing the API of these >>>> functions: https://phabricator.haskell.org/D861#23250 >>>> >>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" thread) >>>> >>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>> wrote: >>>> >>>>> Hmm, that patch doesn't appear to add stack traces to 'Prelude.error', >>>>> which is what Carter wants here. Also, I think it would be done with >>>>> profiling callstacks rather than implicit callstacks. But it's certainly >>>>> also useful to have functions which do the same with implicit callstacks! >>>>> >>>>> >>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>> wrote: >>>>> >>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>> >>>>>> https://phabricator.haskell.org/D578 >>>>>> >>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>> wrote: >>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>> > wrote: >>>>>> >> >>>>>> >> if you can patch prelude error to include stack traces, i will owe >>>>>> you a >>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>> christmas. :) >>>>>> > >>>>>> > >>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>> Looking >>>>>> > forward to ICFP beers either way :D >>>>>> > >>>>>> >> i can't speak for how a different patch might work out, because >>>>>> thats not >>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>> results! >>>>>> >> -Carter >>>>>> >> >>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >>>>>> wrote: >>>>>> >>> >>>>>> >>> Hi Carter! >>>>>> >>> >>>>>> >>> Interesting! This thread, right? >>>>>> >>> >>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>> >>> >>>>>> >>> I haven't tried this as a patch to base, but I'm certain that the >>>>>> core of >>>>>> >>> the proposal has no extra dependencies. Note that the proposal >>>>>> isn't about >>>>>> >>> stack traces in particular - that's just one application of being >>>>>> able to >>>>>> >>> throw exceptions with extra information. >>>>>> >>> >>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>>>> traces, >>>>>> >>> this functionality could be provided outside of >>>>>> `Control.Exception` (though, >>>>>> >>> that does seem like the right place to put it). I'm surprised >>>>>> that the >>>>>> >>> circularity was so problematic, though. Why isn't it sufficient >>>>>> to have an >>>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>>> >>> >>>>>> >>> -Michael >>>>>> >>> >>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>> >>> wrote: >>>>>> >>>> >>>>>> >>>> Hey Michael, >>>>>> >>>> I actually proposed something along these lines that got OK'd by >>>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>>> actually doing >>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>> some nasty >>>>>> >>>> module cycles in base that happen when you try to weave things >>>>>> around so >>>>>> >>>> that the standard error "message here" call includes some stack >>>>>> trace info. >>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>> >>>> >>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work and >>>>>> just >>>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>>> love some >>>>>> >>>> headway on that front. >>>>>> >>>> >>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>> info data >>>>>> >>>> in >7.10 to provide useful stack traces in the default builds >>>>>> for GHC afaik, >>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>> currenlty only work >>>>>> >>>> on profiled builds >>>>>> >>>> >>>>>> >>>> cheers >>>>>> >>>> -Carter >>>>>> >>>> >>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>> mgsloan at gmail.com> >>>>>> >>>> wrote: >>>>>> >>>>> >>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>> could be >>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], but >>>>>> we have >>>>>> >>>>> no generic way to include this information with exceptions. >>>>>> >>>>> >>>>>> >>>>> Proposed Solution >>>>>> >>>>> ================= >>>>>> >>>>> >>>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` >>>>>> to the >>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>> information >>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>> mechanism >>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>> `Exception` type >>>>>> >>>>> works: >>>>>> >>>>> >>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>> >>>>> >>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>> >>>>> SomeExceptionInfo a >>>>>> >>>>> >>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>> >>>>> >>>>>> >>>>> addExceptionInfo >>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>> >>>>> => a -> e -> SomeException >>>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e >>>>>> xs) = >>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>> >>>>> >>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` >>>>>> has, >>>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>>> exception >>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>> necessary >>>>>> >>>>> casting. >>>>>> >>>>> >>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>> constraint >>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a >>>>>> new >>>>>> >>>>> class for this so that: >>>>>> >>>>> >>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>> >>>>> implementation, for when this extra info is presented to the >>>>>> user. >>>>>> >>>>> This function would be invoked by the `show` implementation >>>>>> for >>>>>> >>>>> `SomeException`. >>>>>> >>>>> >>>>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>> acting as >>>>>> >>>>> such an annotation. Having a class for this allows you to >>>>>> ask GHCI >>>>>> >>>>> about all in-scope exception info types via `:info >>>>>> ExceptionInfo`. >>>>>> >>>>> >>>>>> >>>>> Backwards Compatibility >>>>>> >>>>> ======================= >>>>>> >>>>> >>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This >>>>>> means >>>>>> >>>>> that this change could be made without breaking code: >>>>>> >>>>> >>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>> >>>>> >>>>>> >>>>> Note that consumers of this do not need to enable >>>>>> `-XPatternSynonyms`. >>>>>> >>>>> >>>>>> >>>>> Applications >>>>>> >>>>> ============ >>>>>> >>>>> >>>>>> >>>>> Callstacks >>>>>> >>>>> ---------- >>>>>> >>>>> >>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>> callstacks to >>>>>> >>>>> exceptions: >>>>>> >>>>> >>>>>> >>>>> newtype ExceptionCallStack = >>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>>> >>>>> deriving Typeable >>>>>> >>>>> >>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>> >>>>> >>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>> >>>>> throwIOWithStack e = do >>>>>> >>>>> stack <- currentCallStack >>>>>> >>>>> if null stack >>>>>> >>>>> then throwIO e >>>>>> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >>>>>> stack) >>>>>> >>>>> e) >>>>>> >>>>> >>>>>> >>>>> I see little downside for making something like this the default >>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>> `SomeException` >>>>>> >>>>> would add an additional stacktrace to its annotation, much like >>>>>> the >>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>> >>>>> stacktraces would be associated with the exception, rather than >>>>>> just >>>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>> programs, or in >>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>> functioning. >>>>>> >>>>> >>>>>> >>>>> Throwing Exceptions in Handlers >>>>>> >>>>> ------------------------------- >>>>>> >>>>> >>>>>> >>>>> Example: >>>>>> >>>>> >>>>>> >>>>> main = >>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>> >>>>> >>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't >>>>>> see it, >>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a >>>>>> few >>>>>> >>>>> issues: >>>>>> >>>>> >>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>> yielded to >>>>>> >>>>> the user, then the more informative error is lost. >>>>>> >>>>> >>>>>> >>>>> 2. Callers who expect to catch the "Informative error message" >>>>>> won't >>>>>> >>>>> run their handlers for this exception type. >>>>>> >>>>> >>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>>>> >>>>> exception: >>>>>> >>>>> >>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>> >>>>> deriving Typeable >>>>>> >>>>> >>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>> >>>>> displayExceptionInfo fe = >>>>>> >>>>> "thrown while handling " ++ >>>>>> >>>>> displayException (unExceptionCause fe) >>>>>> >>>>> >>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>> >>>>> where >>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>> >>>>> where >>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>> >>>>> >>>>>> >>>>> This implementation of `catch` is written in a >>>>>> backwards-compatible >>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>> still the >>>>>> >>>>> one that gets rethrown. The "original" exception is recorded >>>>>> in the >>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>> >>>>> `__context__` attribute[3]. This was brought to my attention >>>>>> in a >>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>> suppress >>>>>> >>>>> the original exception[5]. >>>>>> >>>>> >>>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>> >>>>> compatibility. With the earlier example, a `catch` handler for >>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>> variant of >>>>>> >>>>> catch which instead throws the original exception. This might >>>>>> be a >>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>> `finally`. >>>>>> >>>>> >>>>>> >>>>> Asynchronous Exceptions >>>>>> >>>>> ----------------------- >>>>>> >>>>> >>>>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring >>>>>> async >>>>>> >>>>> exceptions, is to fork a new thread. This is the approach used >>>>>> by the >>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that >>>>>> we need >>>>>> >>>>> to go to such lengths due to the lack of one bit of information >>>>>> about >>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>> >>>>> >>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >>>>>> enforce >>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>> exception. >>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>> exception is >>>>>> >>>>> synchronous or asynchronous. Here's what this would look like: >>>>>> >>>>> >>>>>> >>>>> data IsAsync = IsAsync >>>>>> >>>>> deriving (Typeable, Show) >>>>>> >>>>> >>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>>> >>>>> >>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>> >>>>> >>>>>> >>>>> The details of this get a bit tricky: What happens if `throwIO` >>>>>> is >>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag >>>>>> set? >>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>> interactions >>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>>>> Vries[8] >>>>>> >>>>> and ghc trac #2558[9]. >>>>>> >>>>> >>>>>> >>>>> Issue: fromException loses info >>>>>> >>>>> =============================== >>>>>> >>>>> >>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>> >>>>> >>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>> usually form >>>>>> >>>>> a prism. In other words, when `fromException` yields a `Just`, >>>>>> you >>>>>> >>>>> should get the same `SomeException` when using `toException` on >>>>>> that >>>>>> >>>>> value. >>>>>> >>>>> >>>>>> >>>>> For example, >>>>>> >>>>> >>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>> throwIO ex >>>>>> >>>>> >>>>>> >>>>> is equivalent to >>>>>> >>>>> >>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>>> >>>>> >>>>>> >>>>> However, with exception info added to just `SomeException`, and >>>>>> no >>>>>> >>>>> changes to existing `Exception` instances, this >>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception type >>>>>> get >>>>>> >>>>> rethrown with less information. >>>>>> >>>>> >>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a >>>>>> field >>>>>> >>>>> to existing `Exception` instances. This would require the use >>>>>> of >>>>>> >>>>> non-default implementations of the `toException` and >>>>>> `fromException` >>>>>> >>>>> instances. >>>>>> >>>>> >>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>> which also >>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>> >>>>> >>>>>> >>>>> [1] >>>>>> >>>>> >>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>> >>>>> [2] >>>>>> >>>>> >>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>> >>>>> [4] >>>>>> >>>>> >>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>> >>>>> [5] >>>>>> >>>>> >>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>> >>>>> >>>>>> >>>>> _______________________________________________ >>>>>> >>>>> Libraries mailing list >>>>>> >>>>> Libraries at haskell.org >>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> >>>>> >>>>>> >>>> >>>>>> >>> >>>>>> >> >>>>>> > >>>>>> > >>>>>> > _______________________________________________ >>>>>> > Libraries mailing list >>>>>> > Libraries at haskell.org >>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> > >>>>>> >>>>> >>>>> >>>> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed Apr 22 02:26:22 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Tue, 21 Apr 2015 22:26:22 -0400 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: in the context of davean's proposal (which i'm still digesting), i'm gonna go -1 on this one. i'm really leery of commiting to any changes to our exception machinery until the dwarf stack trace tooling and associated RTS/exception interaction support is a bit more mature, because i think a lot of other approaches / changes to ghc / base have been driven by the lack of cheap stack traces. This proposal crosses that line, at least for me ;) On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan wrote: > No, this proposal is not specifically about stack traces, that is just one > of the usecases. Instead, this is about a general mechanism for including > extra information with exceptions. The core of this proposal is still > relevant even if the behavior of error / throw / throwTo / etc remain > unchanged. > > I'm not familiar with how the new dwarf stuff will interact with throwing > / displaying exceptions. It seems like this would require having the > debugger break at the throw site, and exceptions would still lack stack > traces. Having informative stack traces is quite orthogonal to having a > good place to store them. > > Note that in my original proposal text I mentioned that this is agnostic > of the particular source of the stack trace. In particular, this could be > used with a profiling stack trace, implicit callstack, or, indeed, these > traces via dwarf. > > -Michael > > On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < > carter.schonwald at gmail.com> wrote: > >> On a more important note: assuming ghc 7.12 has support for informative >> stack traces via dwarf by default, wouldn't that eliminate the need for >> this proposal? Namely : there perhaps should be some reasonable way to talk >> about concatting stack traces perhaps? >> >> Phrased differently: how is the info that should perhaps be in >> informative stack traces not subsuming the info of this proposal? >> >> >> On Tuesday, April 21, 2015, Michael Sloan wrote: >> >>> Ah, but it looks like Niklas does have a patch which adds implicit >>> locations to such functions: https://phabricator.haskell.org/D861 >>> >>> However, there are some issues with changing the API of these functions: >>> https://phabricator.haskell.org/D861#23250 >>> >>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" thread) >>> >>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>> wrote: >>> >>>> Hmm, that patch doesn't appear to add stack traces to 'Prelude.error', >>>> which is what Carter wants here. Also, I think it would be done with >>>> profiling callstacks rather than implicit callstacks. But it's certainly >>>> also useful to have functions which do the same with implicit callstacks! >>>> >>>> >>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>> wrote: >>>> >>>>> Maybe I'm missing something, but isn't this already implemented? >>>>> >>>>> https://phabricator.haskell.org/D578 >>>>> >>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>> wrote: >>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>> > wrote: >>>>> >> >>>>> >> if you can patch prelude error to include stack traces, i will owe >>>>> you a >>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>> christmas. :) >>>>> > >>>>> > >>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>> Looking >>>>> > forward to ICFP beers either way :D >>>>> > >>>>> >> i can't speak for how a different patch might work out, because >>>>> thats not >>>>> >> what I'd tried at the time. If you have a go, please share the >>>>> results! >>>>> >> -Carter >>>>> >> >>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >>>>> wrote: >>>>> >>> >>>>> >>> Hi Carter! >>>>> >>> >>>>> >>> Interesting! This thread, right? >>>>> >>> >>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>> >>> >>>>> >>> I haven't tried this as a patch to base, but I'm certain that the >>>>> core of >>>>> >>> the proposal has no extra dependencies. Note that the proposal >>>>> isn't about >>>>> >>> stack traces in particular - that's just one application of being >>>>> able to >>>>> >>> throw exceptions with extra information. >>>>> >>> >>>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>>> traces, >>>>> >>> this functionality could be provided outside of >>>>> `Control.Exception` (though, >>>>> >>> that does seem like the right place to put it). I'm surprised >>>>> that the >>>>> >>> circularity was so problematic, though. Why isn't it sufficient >>>>> to have an >>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>> >>> >>>>> >>> -Michael >>>>> >>> >>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>> >>> wrote: >>>>> >>>> >>>>> >>>> Hey Michael, >>>>> >>>> I actually proposed something along these lines that got OK'd by >>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>> actually doing >>>>> >>>> the enginering to add the stack traces to exceptions! theres some >>>>> nasty >>>>> >>>> module cycles in base that happen when you try to weave things >>>>> around so >>>>> >>>> that the standard error "message here" call includes some stack >>>>> trace info. >>>>> >>>> Have you tried to do that simple starter patch to base? >>>>> >>>> >>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work and >>>>> just >>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>> love some >>>>> >>>> headway on that front. >>>>> >>>> >>>>> >>>> Theres also some in progress work to use the dwarf debugging info >>>>> data >>>>> >>>> in >7.10 to provide useful stack traces in the default builds for >>>>> GHC afaik, >>>>> >>>> 'cause the stack trace functionality you're pointing at currenlty >>>>> only work >>>>> >>>> on profiled builds >>>>> >>>> >>>>> >>>> cheers >>>>> >>>> -Carter >>>>> >>>> >>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan >>>> > >>>>> >>>> wrote: >>>>> >>>>> >>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>> >>>>> information along with exceptions. For example, exceptions >>>>> could be >>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], but >>>>> we have >>>>> >>>>> no generic way to include this information with exceptions. >>>>> >>>>> >>>>> >>>>> Proposed Solution >>>>> >>>>> ================= >>>>> >>>>> >>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` to >>>>> the >>>>> >>>>> `SomeException` datatype. This list stores additional >>>>> information >>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>> mechanism >>>>> >>>>> which is pretty much identical to the dynamic way the >>>>> `Exception` type >>>>> >>>>> works: >>>>> >>>>> >>>>> >>>>> data SomeException = forall e . Exception e => >>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>> >>>>> >>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>> >>>>> SomeExceptionInfo a >>>>> >>>>> >>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>> >>>>> displayExceptionInfo :: a -> String >>>>> >>>>> >>>>> >>>>> addExceptionInfo >>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>> >>>>> => a -> e -> SomeException >>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e >>>>> xs) = >>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>> >>>>> >>>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` >>>>> has, >>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>> exception >>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>> necessary >>>>> >>>>> casting. >>>>> >>>>> >>>>> >>>>> `SomeExceptionInfo` could validly instead just use the constraint >>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a >>>>> new >>>>> >>>>> class for this so that: >>>>> >>>>> >>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>> >>>>> implementation, for when this extra info is presented to the >>>>> user. >>>>> >>>>> This function would be invoked by the `show` implementation for >>>>> >>>>> `SomeException`. >>>>> >>>>> >>>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>> >>>>> `ExceptionInfo` instance won't be used for anything but acting >>>>> as >>>>> >>>>> such an annotation. Having a class for this allows you to ask >>>>> GHCI >>>>> >>>>> about all in-scope exception info types via `:info >>>>> ExceptionInfo`. >>>>> >>>>> >>>>> >>>>> Backwards Compatibility >>>>> >>>>> ======================= >>>>> >>>>> >>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This >>>>> means >>>>> >>>>> that this change could be made without breaking code: >>>>> >>>>> >>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>> >>>>> >>>>> >>>>> Note that consumers of this do not need to enable >>>>> `-XPatternSynonyms`. >>>>> >>>>> >>>>> >>>>> Applications >>>>> >>>>> ============ >>>>> >>>>> >>>>> >>>>> Callstacks >>>>> >>>>> ---------- >>>>> >>>>> >>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>> callstacks to >>>>> >>>>> exceptions: >>>>> >>>>> >>>>> >>>>> newtype ExceptionCallStack = >>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>> >>>>> deriving Typeable >>>>> >>>>> >>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>> >>>>> >>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>> >>>>> throwIOWithStack e = do >>>>> >>>>> stack <- currentCallStack >>>>> >>>>> if null stack >>>>> >>>>> then throwIO e >>>>> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >>>>> stack) >>>>> >>>>> e) >>>>> >>>>> >>>>> >>>>> I see little downside for making something like this the default >>>>> >>>>> implementation `throwIO`. Each rethrowing of the `SomeException` >>>>> >>>>> would add an additional stacktrace to its annotation, much like >>>>> the >>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>> >>>>> stacktraces would be associated with the exception, rather than >>>>> just >>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>> >>>>> tractable to debug exceptions that occur in concurrent programs, >>>>> or in >>>>> >>>>> programs which frequently throw exceptions during normal >>>>> functioning. >>>>> >>>>> >>>>> >>>>> Throwing Exceptions in Handlers >>>>> >>>>> ------------------------------- >>>>> >>>>> >>>>> >>>>> Example: >>>>> >>>>> >>>>> >>>>> main = >>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>> >>>>> throwIO ObscureCleanupIssue >>>>> >>>>> >>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't see >>>>> it, >>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a few >>>>> >>>>> issues: >>>>> >>>>> >>>>> >>>>> 1. If the exception is handled by the default handler and >>>>> yielded to >>>>> >>>>> the user, then the more informative error is lost. >>>>> >>>>> >>>>> >>>>> 2. Callers who expect to catch the "Informative error message" >>>>> won't >>>>> >>>>> run their handlers for this exception type. >>>>> >>>>> >>>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>>> >>>>> exception: >>>>> >>>>> >>>>> >>>>> data ExceptionCause = ExceptionCause >>>>> >>>>> { unExceptionCause :: SomeException } >>>>> >>>>> deriving Typeable >>>>> >>>>> >>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>> >>>>> displayExceptionInfo fe = >>>>> >>>>> "thrown while handling " ++ >>>>> >>>>> displayException (unExceptionCause fe) >>>>> >>>>> >>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>> >>>>> catch f g = f `oldCatch` handler >>>>> >>>>> where >>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>> >>>>> where >>>>> >>>>> info = ExceptionCause (toException ex) >>>>> >>>>> >>>>> >>>>> This implementation of `catch` is written in a >>>>> backwards-compatible >>>>> >>>>> way, such that the exception thrown during finalization is still >>>>> the >>>>> >>>>> one that gets rethrown. The "original" exception is recorded in >>>>> the >>>>> >>>>> added info. This is the same approach used by Python 3's >>>>> >>>>> `__context__` attribute[3]. This was brought to my attention in >>>>> a >>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>> suppress >>>>> >>>>> the original exception[5]. >>>>> >>>>> >>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>> >>>>> compatibility. With the earlier example, a `catch` handler for >>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>> variant of >>>>> >>>>> catch which instead throws the original exception. This might >>>>> be a >>>>> >>>>> good default for finalization handlers like `bracket` and >>>>> `finally`. >>>>> >>>>> >>>>> >>>>> Asynchronous Exceptions >>>>> >>>>> ----------------------- >>>>> >>>>> >>>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring >>>>> async >>>>> >>>>> exceptions, is to fork a new thread. This is the approach used >>>>> by the >>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that we >>>>> need >>>>> >>>>> to go to such lengths due to the lack of one bit of information >>>>> about >>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>> >>>>> >>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >>>>> enforce >>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>> exception. >>>>> >>>>> Instead, we ought to have a reliable way to know if an exception >>>>> is >>>>> >>>>> synchronous or asynchronous. Here's what this would look like: >>>>> >>>>> >>>>> >>>>> data IsAsync = IsAsync >>>>> >>>>> deriving (Typeable, Show) >>>>> >>>>> >>>>> >>>>> instance ExceptionInfo IsAsync where >>>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>> >>>>> >>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>> >>>>> >>>>> >>>>> The details of this get a bit tricky: What happens if `throwIO` >>>>> is >>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag >>>>> set? >>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>> interactions >>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>>> Vries[8] >>>>> >>>>> and ghc trac #2558[9]. >>>>> >>>>> >>>>> >>>>> Issue: fromException loses info >>>>> >>>>> =============================== >>>>> >>>>> >>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>> >>>>> >>>>> >>>>> Currently, the `toException` and `fromException` methods usually >>>>> form >>>>> >>>>> a prism. In other words, when `fromException` yields a `Just`, >>>>> you >>>>> >>>>> should get the same `SomeException` when using `toException` on >>>>> that >>>>> >>>>> value. >>>>> >>>>> >>>>> >>>>> For example, >>>>> >>>>> >>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>> throwIO ex >>>>> >>>>> >>>>> >>>>> is equivalent to >>>>> >>>>> >>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>> >>>>> >>>>> >>>>> However, with exception info added to just `SomeException`, and >>>>> no >>>>> >>>>> changes to existing `Exception` instances, this >>>>> >>>>> doesn't hold. Exceptions caught as a specific exception type get >>>>> >>>>> rethrown with less information. >>>>> >>>>> >>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a >>>>> field >>>>> >>>>> to existing `Exception` instances. This would require the use of >>>>> >>>>> non-default implementations of the `toException` and >>>>> `fromException` >>>>> >>>>> instances. >>>>> >>>>> >>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>> which also >>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>> >>>>> >>>>> >>>>> [1] >>>>> >>>>> >>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>> >>>>> [2] >>>>> >>>>> >>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>> >>>>> [4] >>>>> >>>>> >>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>> >>>>> [5] >>>>> >>>>> >>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>> >>>>> >>>>> >>>>> _______________________________________________ >>>>> >>>>> Libraries mailing list >>>>> >>>>> Libraries at haskell.org >>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>>>> >>>> >>>>> >>> >>>>> >> >>>>> > >>>>> > >>>>> > _______________________________________________ >>>>> > Libraries mailing list >>>>> > Libraries at haskell.org >>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> > >>>>> >>>> >>>> >>> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Wed Apr 22 03:29:11 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 20:29:11 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Tue, Apr 21, 2015 at 6:40 PM, davean wrote: > So, I've had a number of issues with exceptions. This has been one of > them. I don't really like this proposal as it stands though as it seems to > make catch a specific exception with said extra info more difficult. > > This is data Control.Exception can move around on its own though, right? > The problem really isn't passing it internal, we could just make a (Stack, > SomeException) tuple just fine, in theory I think (I'll admit I've not > actually reviewed the code, and this isn't meant as a complete proposal but > more a thought experiment). The problem is code handling the data and > working with old code while not losing any of the power of the current > system. > > So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a > > Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> IO a > If we want access to the new information, but that's not really > satisfactory. > > Real code regularly wants to (picking an arbitrary instance of Exception) > do: catch :: IO a -> (IOError -> IO a) -> IO a > only we still want new data. > There is no way to always pass around the new data without breaking the Control.Exception API or having users add extra fields to their data types. This is a fundamental issue, and one that my proposal does not seek to address. Infact, I acknowledge it at the end - fromException now loses data. To me it is quite acceptable because: * This is a fundamental limitation of the existing Control.Exception API. This proposal allows us to gracefully update to a new API which does preserve the new info when catching / rethrowing. * These extra annotations are primarily for debugging purposes. It shouldn't be a correctness issue for them to be lost due to rethrowing something other than SomeException. Now one could do something like: catch :: IO a -> (Stack -> IOError -> IO a) > -> IO a > but that is not very upgradable and it breaks existing code. > > But this is just a matter of requesting information, so one could do > something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a > where: data WithStack e = WithStack Stack e > Or maybe one just addes: catchWithContext :: Exception e => IO a -> > (Context -> e -> IO a) -> IO a > Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> IO a > > Now existing code continues to run and we can feed our exception handlers > the data they want, even when we want some specific exception instead of > just any exception. > This is a good idea, which is directly supported by this proposal. You would simply have the implementation of fromException populate the info in your With* datatype. Or, the definition I would prefer: data WithExceptionInfo e = WithExceptionInfo e [SomeExceptionInfo] deriving Typeable instance Exception e => Exception (WithExceptionInfo e) where fromException (SomeExceptionWithInfo e infos) = fmap (\e' -> WithExceptionInfo e' infos) (cast e) toException (WithExceptionInfo e infos) = SomeExceptionWithInfo e infos Does this help clarify my proposal? As far as I can tell there is no contradiction or difference between our proposals. I think you would end up with essentially the same thing I have (maybe with different names ;) ), if you tried implementing your ideas in the context of Control.Exception. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Wed Apr 22 03:43:26 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 20:43:26 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Davean's proposal is essentially the same as mine, restarted and specialized to callstacks. So, I'm not sure why it would make you vote against this. This does more than just stack traces, and is independent of the source of call stacks. What kind of mechanism are you envisioning that would make it redundant to include the callstack with the exception? I can imagine setting a thread local variable to the "last callstack of raise#". However, this does not allow us to accumulate callstacks when the exception is rethrown. Often you care more about the initial throw of the exception, rather than the most recent one. For example, with `+GHC -xc` output, when an exception is caught and rethrown, you'll see the callstacks of all the places it's thrown. This output is rather terrible for real world debugging, though, because it doesn't actually tell you what the exception is. When dealing with a concurrent system where some exceptions occur as part of normal operation, this becomes nightmareish. This proposal solves that problem. If you see even the rough possibility of another solution to this problem, please do tell. -Michael On Tue, Apr 21, 2015 at 7:26 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > in the context of davean's proposal (which i'm still digesting), i'm gonna > go -1 on this one. > > i'm really leery of commiting to any changes to our exception machinery > until the dwarf stack trace tooling and associated RTS/exception > interaction support is a bit more mature, because i think a lot of other > approaches / changes to ghc / base have been driven by the lack of cheap > stack traces. This proposal crosses that line, at least for me ;) > > On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan wrote: > >> No, this proposal is not specifically about stack traces, that is just >> one of the usecases. Instead, this is about a general mechanism for >> including extra information with exceptions. The core of this proposal is >> still relevant even if the behavior of error / throw / throwTo / etc remain >> unchanged. >> >> I'm not familiar with how the new dwarf stuff will interact with throwing >> / displaying exceptions. It seems like this would require having the >> debugger break at the throw site, and exceptions would still lack stack >> traces. Having informative stack traces is quite orthogonal to having a >> good place to store them. >> >> Note that in my original proposal text I mentioned that this is agnostic >> of the particular source of the stack trace. In particular, this could be >> used with a profiling stack trace, implicit callstack, or, indeed, these >> traces via dwarf. >> >> -Michael >> >> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> On a more important note: assuming ghc 7.12 has support for informative >>> stack traces via dwarf by default, wouldn't that eliminate the need for >>> this proposal? Namely : there perhaps should be some reasonable way to talk >>> about concatting stack traces perhaps? >>> >>> Phrased differently: how is the info that should perhaps be in >>> informative stack traces not subsuming the info of this proposal? >>> >>> >>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>> >>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>> locations to such functions: https://phabricator.haskell.org/D861 >>>> >>>> However, there are some issues with changing the API of these >>>> functions: https://phabricator.haskell.org/D861#23250 >>>> >>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" thread) >>>> >>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>> wrote: >>>> >>>>> Hmm, that patch doesn't appear to add stack traces to 'Prelude.error', >>>>> which is what Carter wants here. Also, I think it would be done with >>>>> profiling callstacks rather than implicit callstacks. But it's certainly >>>>> also useful to have functions which do the same with implicit callstacks! >>>>> >>>>> >>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>> wrote: >>>>> >>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>> >>>>>> https://phabricator.haskell.org/D578 >>>>>> >>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>> wrote: >>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>> > wrote: >>>>>> >> >>>>>> >> if you can patch prelude error to include stack traces, i will owe >>>>>> you a >>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>> christmas. :) >>>>>> > >>>>>> > >>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>> Looking >>>>>> > forward to ICFP beers either way :D >>>>>> > >>>>>> >> i can't speak for how a different patch might work out, because >>>>>> thats not >>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>> results! >>>>>> >> -Carter >>>>>> >> >>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan >>>>>> wrote: >>>>>> >>> >>>>>> >>> Hi Carter! >>>>>> >>> >>>>>> >>> Interesting! This thread, right? >>>>>> >>> >>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>> >>> >>>>>> >>> I haven't tried this as a patch to base, but I'm certain that the >>>>>> core of >>>>>> >>> the proposal has no extra dependencies. Note that the proposal >>>>>> isn't about >>>>>> >>> stack traces in particular - that's just one application of being >>>>>> able to >>>>>> >>> throw exceptions with extra information. >>>>>> >>> >>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>>>> traces, >>>>>> >>> this functionality could be provided outside of >>>>>> `Control.Exception` (though, >>>>>> >>> that does seem like the right place to put it). I'm surprised >>>>>> that the >>>>>> >>> circularity was so problematic, though. Why isn't it sufficient >>>>>> to have an >>>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>>> >>> >>>>>> >>> -Michael >>>>>> >>> >>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>> >>> wrote: >>>>>> >>>> >>>>>> >>>> Hey Michael, >>>>>> >>>> I actually proposed something along these lines that got OK'd by >>>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>>> actually doing >>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>> some nasty >>>>>> >>>> module cycles in base that happen when you try to weave things >>>>>> around so >>>>>> >>>> that the standard error "message here" call includes some stack >>>>>> trace info. >>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>> >>>> >>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work and >>>>>> just >>>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>>> love some >>>>>> >>>> headway on that front. >>>>>> >>>> >>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>> info data >>>>>> >>>> in >7.10 to provide useful stack traces in the default builds >>>>>> for GHC afaik, >>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>> currenlty only work >>>>>> >>>> on profiled builds >>>>>> >>>> >>>>>> >>>> cheers >>>>>> >>>> -Carter >>>>>> >>>> >>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>> mgsloan at gmail.com> >>>>>> >>>> wrote: >>>>>> >>>>> >>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>> could be >>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], but >>>>>> we have >>>>>> >>>>> no generic way to include this information with exceptions. >>>>>> >>>>> >>>>>> >>>>> Proposed Solution >>>>>> >>>>> ================= >>>>>> >>>>> >>>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` >>>>>> to the >>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>> information >>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>> mechanism >>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>> `Exception` type >>>>>> >>>>> works: >>>>>> >>>>> >>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>> >>>>> >>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>> >>>>> SomeExceptionInfo a >>>>>> >>>>> >>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>> >>>>> >>>>>> >>>>> addExceptionInfo >>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>> >>>>> => a -> e -> SomeException >>>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e >>>>>> xs) = >>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>> >>>>> >>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` >>>>>> has, >>>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>>> exception >>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>> necessary >>>>>> >>>>> casting. >>>>>> >>>>> >>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>> constraint >>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have a >>>>>> new >>>>>> >>>>> class for this so that: >>>>>> >>>>> >>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>> >>>>> implementation, for when this extra info is presented to the >>>>>> user. >>>>>> >>>>> This function would be invoked by the `show` implementation >>>>>> for >>>>>> >>>>> `SomeException`. >>>>>> >>>>> >>>>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>> acting as >>>>>> >>>>> such an annotation. Having a class for this allows you to >>>>>> ask GHCI >>>>>> >>>>> about all in-scope exception info types via `:info >>>>>> ExceptionInfo`. >>>>>> >>>>> >>>>>> >>>>> Backwards Compatibility >>>>>> >>>>> ======================= >>>>>> >>>>> >>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. This >>>>>> means >>>>>> >>>>> that this change could be made without breaking code: >>>>>> >>>>> >>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>> >>>>> >>>>>> >>>>> Note that consumers of this do not need to enable >>>>>> `-XPatternSynonyms`. >>>>>> >>>>> >>>>>> >>>>> Applications >>>>>> >>>>> ============ >>>>>> >>>>> >>>>>> >>>>> Callstacks >>>>>> >>>>> ---------- >>>>>> >>>>> >>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>> callstacks to >>>>>> >>>>> exceptions: >>>>>> >>>>> >>>>>> >>>>> newtype ExceptionCallStack = >>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>>> >>>>> deriving Typeable >>>>>> >>>>> >>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>> >>>>> >>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>> >>>>> throwIOWithStack e = do >>>>>> >>>>> stack <- currentCallStack >>>>>> >>>>> if null stack >>>>>> >>>>> then throwIO e >>>>>> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >>>>>> stack) >>>>>> >>>>> e) >>>>>> >>>>> >>>>>> >>>>> I see little downside for making something like this the default >>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>> `SomeException` >>>>>> >>>>> would add an additional stacktrace to its annotation, much like >>>>>> the >>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>> >>>>> stacktraces would be associated with the exception, rather than >>>>>> just >>>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>> programs, or in >>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>> functioning. >>>>>> >>>>> >>>>>> >>>>> Throwing Exceptions in Handlers >>>>>> >>>>> ------------------------------- >>>>>> >>>>> >>>>>> >>>>> Example: >>>>>> >>>>> >>>>>> >>>>> main = >>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>> >>>>> >>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't >>>>>> see it, >>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a >>>>>> few >>>>>> >>>>> issues: >>>>>> >>>>> >>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>> yielded to >>>>>> >>>>> the user, then the more informative error is lost. >>>>>> >>>>> >>>>>> >>>>> 2. Callers who expect to catch the "Informative error message" >>>>>> won't >>>>>> >>>>> run their handlers for this exception type. >>>>>> >>>>> >>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>>>> >>>>> exception: >>>>>> >>>>> >>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>> >>>>> deriving Typeable >>>>>> >>>>> >>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>> >>>>> displayExceptionInfo fe = >>>>>> >>>>> "thrown while handling " ++ >>>>>> >>>>> displayException (unExceptionCause fe) >>>>>> >>>>> >>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>> >>>>> where >>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>> >>>>> where >>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>> >>>>> >>>>>> >>>>> This implementation of `catch` is written in a >>>>>> backwards-compatible >>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>> still the >>>>>> >>>>> one that gets rethrown. The "original" exception is recorded >>>>>> in the >>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>> >>>>> `__context__` attribute[3]. This was brought to my attention >>>>>> in a >>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>> suppress >>>>>> >>>>> the original exception[5]. >>>>>> >>>>> >>>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>> >>>>> compatibility. With the earlier example, a `catch` handler for >>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't the >>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>> variant of >>>>>> >>>>> catch which instead throws the original exception. This might >>>>>> be a >>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>> `finally`. >>>>>> >>>>> >>>>>> >>>>> Asynchronous Exceptions >>>>>> >>>>> ----------------------- >>>>>> >>>>> >>>>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring >>>>>> async >>>>>> >>>>> exceptions, is to fork a new thread. This is the approach used >>>>>> by the >>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that >>>>>> we need >>>>>> >>>>> to go to such lengths due to the lack of one bit of information >>>>>> about >>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>> >>>>> >>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >>>>>> enforce >>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>> exception. >>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>> exception is >>>>>> >>>>> synchronous or asynchronous. Here's what this would look like: >>>>>> >>>>> >>>>>> >>>>> data IsAsync = IsAsync >>>>>> >>>>> deriving (Typeable, Show) >>>>>> >>>>> >>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>>> >>>>> >>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>> >>>>> >>>>>> >>>>> The details of this get a bit tricky: What happens if `throwIO` >>>>>> is >>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` flag >>>>>> set? >>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>> interactions >>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>>>> Vries[8] >>>>>> >>>>> and ghc trac #2558[9]. >>>>>> >>>>> >>>>>> >>>>> Issue: fromException loses info >>>>>> >>>>> =============================== >>>>>> >>>>> >>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>> >>>>> >>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>> usually form >>>>>> >>>>> a prism. In other words, when `fromException` yields a `Just`, >>>>>> you >>>>>> >>>>> should get the same `SomeException` when using `toException` on >>>>>> that >>>>>> >>>>> value. >>>>>> >>>>> >>>>>> >>>>> For example, >>>>>> >>>>> >>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>> throwIO ex >>>>>> >>>>> >>>>>> >>>>> is equivalent to >>>>>> >>>>> >>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>>> >>>>> >>>>>> >>>>> However, with exception info added to just `SomeException`, and >>>>>> no >>>>>> >>>>> changes to existing `Exception` instances, this >>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception type >>>>>> get >>>>>> >>>>> rethrown with less information. >>>>>> >>>>> >>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a >>>>>> field >>>>>> >>>>> to existing `Exception` instances. This would require the use >>>>>> of >>>>>> >>>>> non-default implementations of the `toException` and >>>>>> `fromException` >>>>>> >>>>> instances. >>>>>> >>>>> >>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>> which also >>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>> >>>>> >>>>>> >>>>> [1] >>>>>> >>>>> >>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>> >>>>> [2] >>>>>> >>>>> >>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>> >>>>> [4] >>>>>> >>>>> >>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>> >>>>> [5] >>>>>> >>>>> >>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>> >>>>> >>>>>> >>>>> _______________________________________________ >>>>>> >>>>> Libraries mailing list >>>>>> >>>>> Libraries at haskell.org >>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> >>>>> >>>>>> >>>> >>>>>> >>> >>>>>> >> >>>>>> > >>>>>> > >>>>>> > _______________________________________________ >>>>>> > Libraries mailing list >>>>>> > Libraries at haskell.org >>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> > >>>>>> >>>>> >>>>> >>>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Wed Apr 22 03:50:59 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Tue, 21 Apr 2015 20:50:59 -0700 Subject: Exceptions with Context Re: Proposal: Add exception info In-Reply-To: References: Message-ID: Either I am misunderstanding davean's proposal, or you are misunderstanding mine. Namely: * How is his proposal more extensible? His specializes it to just passing callstack information. * I'm not sure exactly how he proposes to change the catch. If it's changed to always preserve the extra exception info, then this will be a massive API breakage. -Michael On Tue, Apr 21, 2015 at 7:23 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > hrm, i like this proposal more, and it seems like with some fleshing out > it can be strictly more extensible yet backwards compatible than michael's > > I'll need to mull it a bit more before I cast my vote, but this seems to > sketch out a design that provides the same information, but in a more > extensible/backwards compatible fashion (at least in a first cut of > thinking about it) > > (i'm splitting this into a new thread so the discussions dont get mixed up) > > On Tue, Apr 21, 2015 at 9:40 PM, davean wrote: > >> So, I've had a number of issues with exceptions. This has been one of >> them. I don't really like this proposal as it stands though as it seems to >> make catch a specific exception with said extra info more difficult. >> >> This is data Control.Exception can move around on its own though, right? >> The problem really isn't passing it internal, we could just make a (Stack, >> SomeException) tuple just fine, in theory I think (I'll admit I've not >> actually reviewed the code, and this isn't meant as a complete proposal but >> more a thought experiment). The problem is code handling the data and >> working with old code while not losing any of the power of the current >> system. >> >> So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a >> >> Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> IO >> a >> If we want access to the new information, but that's not really >> satisfactory. >> >> Real code regularly wants to (picking an arbitrary instance of Exception) >> do: catch :: IO a -> (IOError -> IO a) -> IO a >> only we still want new data. >> >> Now one could do something like: catch :: IO a -> (Stack -> IOError -> IO >> a) -> IO a >> but that is not very upgradable and it breaks existing code. >> >> But this is just a matter of requesting information, so one could do >> something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a >> where: data WithStack e = WithStack Stack e >> Or maybe one just addes: catchWithContext :: Exception e => IO a -> >> (Context -> e -> IO a) -> IO a >> Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> IO a >> >> Now existing code continues to run and we can feed our exception handlers >> the data they want, even when we want some specific exception instead of >> just any exception. >> >> Now that still leave a hole in what I want out of exceptions. We're still >> short of programmatic interrogating them, or even telling what the >> exception was if we didn't expect it! >> >> Consider AssertionFailed >> . >> Its show instance is "showsPrec _ (AssertionFailed err) = showString err", >> so if we print out the SomeException, we get whatever string is in >> AssertionFailed. Which is great if that string makes sense. But you see >> that on your console and its a bit baffling if it doesn't. It could even be >> a lie, I can make that say something that looks like its a different >> exception. We can use the Typeable instance so the program can tell them >> apart at least though. Which works as long as the exception is >> single-constructor, or has a well-behaved show instance. What if we come >> across a monstrosity like >> http://hackage.haskell.org/package/http-conduit-2.1.5/docs/Network-HTTP-Conduit.html#g:12 >> and it doesn't have a nice show instance that says which on it is? If >> Exception added a Data constraint we could actually pull apart these >> exceptions and start to make proper sense of them reliably. >> >> Once you have that there are quite a few useful things you can do with >> the exceptions you didn't expect. Currently you could only do them by >> enumerating every possible exception which of course doesn't work for the >> unexpected. >> >> On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan wrote: >> >>> No, this proposal is not specifically about stack traces, that is just >>> one of the usecases. Instead, this is about a general mechanism for >>> including extra information with exceptions. The core of this proposal is >>> still relevant even if the behavior of error / throw / throwTo / etc remain >>> unchanged. >>> >>> I'm not familiar with how the new dwarf stuff will interact with >>> throwing / displaying exceptions. It seems like this would require having >>> the debugger break at the throw site, and exceptions would still lack stack >>> traces. Having informative stack traces is quite orthogonal to having a >>> good place to store them. >>> >>> Note that in my original proposal text I mentioned that this is agnostic >>> of the particular source of the stack trace. In particular, this could be >>> used with a profiling stack trace, implicit callstack, or, indeed, these >>> traces via dwarf. >>> >>> -Michael >>> >>> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >>> carter.schonwald at gmail.com> wrote: >>> >>>> On a more important note: assuming ghc 7.12 has support for informative >>>> stack traces via dwarf by default, wouldn't that eliminate the need for >>>> this proposal? Namely : there perhaps should be some reasonable way to talk >>>> about concatting stack traces perhaps? >>>> >>>> Phrased differently: how is the info that should perhaps be in >>>> informative stack traces not subsuming the info of this proposal? >>>> >>>> >>>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>>> >>>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>>> locations to such functions: https://phabricator.haskell.org/D861 >>>>> >>>>> However, there are some issues with changing the API of these >>>>> functions: https://phabricator.haskell.org/D861#23250 >>>>> >>>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" >>>>> thread) >>>>> >>>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>>> wrote: >>>>> >>>>>> Hmm, that patch doesn't appear to add stack traces to >>>>>> 'Prelude.error', which is what Carter wants here. Also, I think it would >>>>>> be done with profiling callstacks rather than implicit callstacks. But >>>>>> it's certainly also useful to have functions which do the same with >>>>>> implicit callstacks! >>>>>> >>>>>> >>>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>>> wrote: >>>>>> >>>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>>> >>>>>>> https://phabricator.haskell.org/D578 >>>>>>> >>>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>>> wrote: >>>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>>> > wrote: >>>>>>> >> >>>>>>> >> if you can patch prelude error to include stack traces, i will >>>>>>> owe you a >>>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>>> christmas. :) >>>>>>> > >>>>>>> > >>>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>>> Looking >>>>>>> > forward to ICFP beers either way :D >>>>>>> > >>>>>>> >> i can't speak for how a different patch might work out, because >>>>>>> thats not >>>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>>> results! >>>>>>> >> -Carter >>>>>>> >> >>>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan < >>>>>>> mgsloan at gmail.com> wrote: >>>>>>> >>> >>>>>>> >>> Hi Carter! >>>>>>> >>> >>>>>>> >>> Interesting! This thread, right? >>>>>>> >>> >>>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>>> >>> >>>>>>> >>> I haven't tried this as a patch to base, but I'm certain that >>>>>>> the core of >>>>>>> >>> the proposal has no extra dependencies. Note that the proposal >>>>>>> isn't about >>>>>>> >>> stack traces in particular - that's just one application of >>>>>>> being able to >>>>>>> >>> throw exceptions with extra information. >>>>>>> >>> >>>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>>>>> traces, >>>>>>> >>> this functionality could be provided outside of >>>>>>> `Control.Exception` (though, >>>>>>> >>> that does seem like the right place to put it). I'm surprised >>>>>>> that the >>>>>>> >>> circularity was so problematic, though. Why isn't it sufficient >>>>>>> to have an >>>>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>>>> >>> >>>>>>> >>> -Michael >>>>>>> >>> >>>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>>> >>> wrote: >>>>>>> >>>> >>>>>>> >>>> Hey Michael, >>>>>>> >>>> I actually proposed something along these lines that got OK'd by >>>>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>>>> actually doing >>>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>>> some nasty >>>>>>> >>>> module cycles in base that happen when you try to weave things >>>>>>> around so >>>>>>> >>>> that the standard error "message here" call includes some stack >>>>>>> trace info. >>>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>>> >>>> >>>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work >>>>>>> and just >>>>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>>>> love some >>>>>>> >>>> headway on that front. >>>>>>> >>>> >>>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>>> info data >>>>>>> >>>> in >7.10 to provide useful stack traces in the default builds >>>>>>> for GHC afaik, >>>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>>> currenlty only work >>>>>>> >>>> on profiled builds >>>>>>> >>>> >>>>>>> >>>> cheers >>>>>>> >>>> -Carter >>>>>>> >>>> >>>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>>> mgsloan at gmail.com> >>>>>>> >>>> wrote: >>>>>>> >>>>> >>>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>>> could be >>>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], but >>>>>>> we have >>>>>>> >>>>> no generic way to include this information with exceptions. >>>>>>> >>>>> >>>>>>> >>>>> Proposed Solution >>>>>>> >>>>> ================= >>>>>>> >>>>> >>>>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` >>>>>>> to the >>>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>>> information >>>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>>> mechanism >>>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>>> `Exception` type >>>>>>> >>>>> works: >>>>>>> >>>>> >>>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>>> >>>>> >>>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>>> >>>>> SomeExceptionInfo a >>>>>>> >>>>> >>>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>>> >>>>> >>>>>>> >>>>> addExceptionInfo >>>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>>> >>>>> => a -> e -> SomeException >>>>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e >>>>>>> xs) = >>>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>>> >>>>> >>>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` >>>>>>> has, >>>>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>>>> exception >>>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>>> necessary >>>>>>> >>>>> casting. >>>>>>> >>>>> >>>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>>> constraint >>>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have >>>>>>> a new >>>>>>> >>>>> class for this so that: >>>>>>> >>>>> >>>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>>> >>>>> implementation, for when this extra info is presented to the >>>>>>> user. >>>>>>> >>>>> This function would be invoked by the `show` implementation >>>>>>> for >>>>>>> >>>>> `SomeException`. >>>>>>> >>>>> >>>>>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>>> acting as >>>>>>> >>>>> such an annotation. Having a class for this allows you to >>>>>>> ask GHCI >>>>>>> >>>>> about all in-scope exception info types via `:info >>>>>>> ExceptionInfo`. >>>>>>> >>>>> >>>>>>> >>>>> Backwards Compatibility >>>>>>> >>>>> ======================= >>>>>>> >>>>> >>>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. >>>>>>> This means >>>>>>> >>>>> that this change could be made without breaking code: >>>>>>> >>>>> >>>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>>> >>>>> >>>>>>> >>>>> Note that consumers of this do not need to enable >>>>>>> `-XPatternSynonyms`. >>>>>>> >>>>> >>>>>>> >>>>> Applications >>>>>>> >>>>> ============ >>>>>>> >>>>> >>>>>>> >>>>> Callstacks >>>>>>> >>>>> ---------- >>>>>>> >>>>> >>>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>>> callstacks to >>>>>>> >>>>> exceptions: >>>>>>> >>>>> >>>>>>> >>>>> newtype ExceptionCallStack = >>>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>>>> >>>>> deriving Typeable >>>>>>> >>>>> >>>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>>> >>>>> >>>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>>> >>>>> throwIOWithStack e = do >>>>>>> >>>>> stack <- currentCallStack >>>>>>> >>>>> if null stack >>>>>>> >>>>> then throwIO e >>>>>>> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >>>>>>> stack) >>>>>>> >>>>> e) >>>>>>> >>>>> >>>>>>> >>>>> I see little downside for making something like this the >>>>>>> default >>>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>>> `SomeException` >>>>>>> >>>>> would add an additional stacktrace to its annotation, much >>>>>>> like the >>>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>>> >>>>> stacktraces would be associated with the exception, rather >>>>>>> than just >>>>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>>> programs, or in >>>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>>> functioning. >>>>>>> >>>>> >>>>>>> >>>>> Throwing Exceptions in Handlers >>>>>>> >>>>> ------------------------------- >>>>>>> >>>>> >>>>>>> >>>>> Example: >>>>>>> >>>>> >>>>>>> >>>>> main = >>>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>>> >>>>> >>>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't >>>>>>> see it, >>>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a >>>>>>> few >>>>>>> >>>>> issues: >>>>>>> >>>>> >>>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>>> yielded to >>>>>>> >>>>> the user, then the more informative error is lost. >>>>>>> >>>>> >>>>>>> >>>>> 2. Callers who expect to catch the "Informative error message" >>>>>>> won't >>>>>>> >>>>> run their handlers for this exception type. >>>>>>> >>>>> >>>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>>>>> >>>>> exception: >>>>>>> >>>>> >>>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>>> >>>>> deriving Typeable >>>>>>> >>>>> >>>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>>> >>>>> displayExceptionInfo fe = >>>>>>> >>>>> "thrown while handling " ++ >>>>>>> >>>>> displayException (unExceptionCause fe) >>>>>>> >>>>> >>>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>>> >>>>> where >>>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>>> >>>>> where >>>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>>> >>>>> >>>>>>> >>>>> This implementation of `catch` is written in a >>>>>>> backwards-compatible >>>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>>> still the >>>>>>> >>>>> one that gets rethrown. The "original" exception is recorded >>>>>>> in the >>>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>>> >>>>> `__context__` attribute[3]. This was brought to my attention >>>>>>> in a >>>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>>> suppress >>>>>>> >>>>> the original exception[5]. >>>>>>> >>>>> >>>>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>>> >>>>> compatibility. With the earlier example, a `catch` handler for >>>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't >>>>>>> the >>>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>>> variant of >>>>>>> >>>>> catch which instead throws the original exception. This might >>>>>>> be a >>>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>>> `finally`. >>>>>>> >>>>> >>>>>>> >>>>> Asynchronous Exceptions >>>>>>> >>>>> ----------------------- >>>>>>> >>>>> >>>>>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring >>>>>>> async >>>>>>> >>>>> exceptions, is to fork a new thread. This is the approach >>>>>>> used by the >>>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that >>>>>>> we need >>>>>>> >>>>> to go to such lengths due to the lack of one bit of >>>>>>> information about >>>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>>> >>>>> >>>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >>>>>>> enforce >>>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>>> exception. >>>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>>> exception is >>>>>>> >>>>> synchronous or asynchronous. Here's what this would look like: >>>>>>> >>>>> >>>>>>> >>>>> data IsAsync = IsAsync >>>>>>> >>>>> deriving (Typeable, Show) >>>>>>> >>>>> >>>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>>>> >>>>> >>>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>>> >>>>> >>>>>>> >>>>> The details of this get a bit tricky: What happens if >>>>>>> `throwIO` is >>>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` >>>>>>> flag set? >>>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>>> interactions >>>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>>>>> Vries[8] >>>>>>> >>>>> and ghc trac #2558[9]. >>>>>>> >>>>> >>>>>>> >>>>> Issue: fromException loses info >>>>>>> >>>>> =============================== >>>>>>> >>>>> >>>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>>> >>>>> >>>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>>> usually form >>>>>>> >>>>> a prism. In other words, when `fromException` yields a >>>>>>> `Just`, you >>>>>>> >>>>> should get the same `SomeException` when using `toException` >>>>>>> on that >>>>>>> >>>>> value. >>>>>>> >>>>> >>>>>>> >>>>> For example, >>>>>>> >>>>> >>>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>>> throwIO ex >>>>>>> >>>>> >>>>>>> >>>>> is equivalent to >>>>>>> >>>>> >>>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>>>> >>>>> >>>>>>> >>>>> However, with exception info added to just `SomeException`, >>>>>>> and no >>>>>>> >>>>> changes to existing `Exception` instances, this >>>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception type >>>>>>> get >>>>>>> >>>>> rethrown with less information. >>>>>>> >>>>> >>>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a >>>>>>> field >>>>>>> >>>>> to existing `Exception` instances. This would require the use >>>>>>> of >>>>>>> >>>>> non-default implementations of the `toException` and >>>>>>> `fromException` >>>>>>> >>>>> instances. >>>>>>> >>>>> >>>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>>> which also >>>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>>> >>>>> >>>>>>> >>>>> [1] >>>>>>> >>>>> >>>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>>> >>>>> [2] >>>>>>> >>>>> >>>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>>> >>>>> [4] >>>>>>> >>>>> >>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>>> >>>>> [5] >>>>>>> >>>>> >>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>>> >>>>> >>>>>>> >>>>> _______________________________________________ >>>>>>> >>>>> Libraries mailing list >>>>>>> >>>>> Libraries at haskell.org >>>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>> >>>>> >>>>>>> >>>> >>>>>>> >>> >>>>>>> >> >>>>>>> > >>>>>>> > >>>>>>> > _______________________________________________ >>>>>>> > Libraries mailing list >>>>>>> > Libraries at haskell.org >>>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>> > >>>>>>> >>>>>> >>>>>> >>>>> >>> >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed Apr 22 04:08:27 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Wed, 22 Apr 2015 00:08:27 -0400 Subject: Exceptions with Context Re: Proposal: Add exception info In-Reply-To: References: Message-ID: no michael, Daveans proposal is that we add certain catchWithExtraInfo :: Exception e => IO a -> (ExtraInfo -> e -> IO a ) -> IO a style operations to the exceptions modules, for various choices of "extraInfo" The idea being, NO current exception codes should have to change. Nor does SomeException need to change. i will try to articulate my concerns about your proposed design in more details on the other proposal thread after i've had a bit more sleep and thought about it more On Tue, Apr 21, 2015 at 11:50 PM, Michael Sloan wrote: > Either I am misunderstanding davean's proposal, or you are > misunderstanding mine. Namely: > > * How is his proposal more extensible? His specializes it to just passing > callstack information. > > * I'm not sure exactly how he proposes to change the catch. If it's > changed to always preserve the extra exception info, then this will be a > massive API breakage. > > -Michael > > On Tue, Apr 21, 2015 at 7:23 PM, Carter Schonwald < > carter.schonwald at gmail.com> wrote: > >> hrm, i like this proposal more, and it seems like with some fleshing out >> it can be strictly more extensible yet backwards compatible than michael's >> >> I'll need to mull it a bit more before I cast my vote, but this seems to >> sketch out a design that provides the same information, but in a more >> extensible/backwards compatible fashion (at least in a first cut of >> thinking about it) >> >> (i'm splitting this into a new thread so the discussions dont get mixed >> up) >> >> On Tue, Apr 21, 2015 at 9:40 PM, davean wrote: >> >>> So, I've had a number of issues with exceptions. This has been one of >>> them. I don't really like this proposal as it stands though as it seems to >>> make catch a specific exception with said extra info more difficult. >>> >>> This is data Control.Exception can move around on its own though, right? >>> The problem really isn't passing it internal, we could just make a (Stack, >>> SomeException) tuple just fine, in theory I think (I'll admit I've not >>> actually reviewed the code, and this isn't meant as a complete proposal but >>> more a thought experiment). The problem is code handling the data and >>> working with old code while not losing any of the power of the current >>> system. >>> >>> So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a >>> >>> Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> >>> IO a >>> If we want access to the new information, but that's not really >>> satisfactory. >>> >>> Real code regularly wants to (picking an arbitrary instance of >>> Exception) do: catch :: IO a -> (IOError -> IO a) -> IO a >>> only we still want new data. >>> >>> Now one could do something like: catch :: IO a -> (Stack -> IOError -> >>> IO a) -> IO a >>> but that is not very upgradable and it breaks existing code. >>> >>> But this is just a matter of requesting information, so one could do >>> something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a >>> where: data WithStack e = WithStack Stack e >>> Or maybe one just addes: catchWithContext :: Exception e => IO a -> >>> (Context -> e -> IO a) -> IO a >>> Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> IO a >>> >>> Now existing code continues to run and we can feed our exception >>> handlers the data they want, even when we want some specific exception >>> instead of just any exception. >>> >>> Now that still leave a hole in what I want out of exceptions. We're >>> still short of programmatic interrogating them, or even telling what the >>> exception was if we didn't expect it! >>> >>> Consider AssertionFailed >>> . >>> Its show instance is "showsPrec _ (AssertionFailed err) = showString err", >>> so if we print out the SomeException, we get whatever string is in >>> AssertionFailed. Which is great if that string makes sense. But you see >>> that on your console and its a bit baffling if it doesn't. It could even be >>> a lie, I can make that say something that looks like its a different >>> exception. We can use the Typeable instance so the program can tell them >>> apart at least though. Which works as long as the exception is >>> single-constructor, or has a well-behaved show instance. What if we come >>> across a monstrosity like >>> http://hackage.haskell.org/package/http-conduit-2.1.5/docs/Network-HTTP-Conduit.html#g:12 >>> and it doesn't have a nice show instance that says which on it is? If >>> Exception added a Data constraint we could actually pull apart these >>> exceptions and start to make proper sense of them reliably. >>> >>> Once you have that there are quite a few useful things you can do with >>> the exceptions you didn't expect. Currently you could only do them by >>> enumerating every possible exception which of course doesn't work for the >>> unexpected. >>> >>> On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan >>> wrote: >>> >>>> No, this proposal is not specifically about stack traces, that is just >>>> one of the usecases. Instead, this is about a general mechanism for >>>> including extra information with exceptions. The core of this proposal is >>>> still relevant even if the behavior of error / throw / throwTo / etc remain >>>> unchanged. >>>> >>>> I'm not familiar with how the new dwarf stuff will interact with >>>> throwing / displaying exceptions. It seems like this would require having >>>> the debugger break at the throw site, and exceptions would still lack stack >>>> traces. Having informative stack traces is quite orthogonal to having a >>>> good place to store them. >>>> >>>> Note that in my original proposal text I mentioned that this is >>>> agnostic of the particular source of the stack trace. In particular, this >>>> could be used with a profiling stack trace, implicit callstack, or, indeed, >>>> these traces via dwarf. >>>> >>>> -Michael >>>> >>>> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >>>> carter.schonwald at gmail.com> wrote: >>>> >>>>> On a more important note: assuming ghc 7.12 has support for >>>>> informative stack traces via dwarf by default, wouldn't that eliminate the >>>>> need for this proposal? Namely : there perhaps should be some reasonable >>>>> way to talk about concatting stack traces perhaps? >>>>> >>>>> Phrased differently: how is the info that should perhaps be in >>>>> informative stack traces not subsuming the info of this proposal? >>>>> >>>>> >>>>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>>>> >>>>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>>>> locations to such functions: https://phabricator.haskell.org/D861 >>>>>> >>>>>> However, there are some issues with changing the API of these >>>>>> functions: https://phabricator.haskell.org/D861#23250 >>>>>> >>>>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" >>>>>> thread) >>>>>> >>>>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>>>> wrote: >>>>>> >>>>>>> Hmm, that patch doesn't appear to add stack traces to >>>>>>> 'Prelude.error', which is what Carter wants here. Also, I think it would >>>>>>> be done with profiling callstacks rather than implicit callstacks. But >>>>>>> it's certainly also useful to have functions which do the same with >>>>>>> implicit callstacks! >>>>>>> >>>>>>> >>>>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>>>> wrote: >>>>>>> >>>>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>>>> >>>>>>>> https://phabricator.haskell.org/D578 >>>>>>>> >>>>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>>>> wrote: >>>>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>>>> > wrote: >>>>>>>> >> >>>>>>>> >> if you can patch prelude error to include stack traces, i will >>>>>>>> owe you a >>>>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>>>> christmas. :) >>>>>>>> > >>>>>>>> > >>>>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>>>> Looking >>>>>>>> > forward to ICFP beers either way :D >>>>>>>> > >>>>>>>> >> i can't speak for how a different patch might work out, because >>>>>>>> thats not >>>>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>>>> results! >>>>>>>> >> -Carter >>>>>>>> >> >>>>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan < >>>>>>>> mgsloan at gmail.com> wrote: >>>>>>>> >>> >>>>>>>> >>> Hi Carter! >>>>>>>> >>> >>>>>>>> >>> Interesting! This thread, right? >>>>>>>> >>> >>>>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>>>> >>> >>>>>>>> >>> I haven't tried this as a patch to base, but I'm certain that >>>>>>>> the core of >>>>>>>> >>> the proposal has no extra dependencies. Note that the proposal >>>>>>>> isn't about >>>>>>>> >>> stack traces in particular - that's just one application of >>>>>>>> being able to >>>>>>>> >>> throw exceptions with extra information. >>>>>>>> >>> >>>>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>>>>>> traces, >>>>>>>> >>> this functionality could be provided outside of >>>>>>>> `Control.Exception` (though, >>>>>>>> >>> that does seem like the right place to put it). I'm surprised >>>>>>>> that the >>>>>>>> >>> circularity was so problematic, though. Why isn't it >>>>>>>> sufficient to have an >>>>>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>>>>> >>> >>>>>>>> >>> -Michael >>>>>>>> >>> >>>>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>>>> >>> wrote: >>>>>>>> >>>> >>>>>>>> >>>> Hey Michael, >>>>>>>> >>>> I actually proposed something along these lines that got OK'd >>>>>>>> by >>>>>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>>>>> actually doing >>>>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>>>> some nasty >>>>>>>> >>>> module cycles in base that happen when you try to weave things >>>>>>>> around so >>>>>>>> >>>> that the standard error "message here" call includes some >>>>>>>> stack trace info. >>>>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>>>> >>>> >>>>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work >>>>>>>> and just >>>>>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>>>>> love some >>>>>>>> >>>> headway on that front. >>>>>>>> >>>> >>>>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>>>> info data >>>>>>>> >>>> in >7.10 to provide useful stack traces in the default builds >>>>>>>> for GHC afaik, >>>>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>>>> currenlty only work >>>>>>>> >>>> on profiled builds >>>>>>>> >>>> >>>>>>>> >>>> cheers >>>>>>>> >>>> -Carter >>>>>>>> >>>> >>>>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>>>> mgsloan at gmail.com> >>>>>>>> >>>> wrote: >>>>>>>> >>>>> >>>>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>>>> could be >>>>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], >>>>>>>> but we have >>>>>>>> >>>>> no generic way to include this information with exceptions. >>>>>>>> >>>>> >>>>>>>> >>>>> Proposed Solution >>>>>>>> >>>>> ================= >>>>>>>> >>>>> >>>>>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` >>>>>>>> to the >>>>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>>>> information >>>>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>>>> mechanism >>>>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>>>> `Exception` type >>>>>>>> >>>>> works: >>>>>>>> >>>>> >>>>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>>>> >>>>> >>>>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>>>> >>>>> SomeExceptionInfo a >>>>>>>> >>>>> >>>>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>>>> >>>>> >>>>>>>> >>>>> addExceptionInfo >>>>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>>>> >>>>> => a -> e -> SomeException >>>>>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo >>>>>>>> e xs) = >>>>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>>>> >>>>> >>>>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that >>>>>>>> `Exception` has, >>>>>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>>>>> exception >>>>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>>>> necessary >>>>>>>> >>>>> casting. >>>>>>>> >>>>> >>>>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>>>> constraint >>>>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have >>>>>>>> a new >>>>>>>> >>>>> class for this so that: >>>>>>>> >>>>> >>>>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>>>> >>>>> implementation, for when this extra info is presented to >>>>>>>> the user. >>>>>>>> >>>>> This function would be invoked by the `show` implementation >>>>>>>> for >>>>>>>> >>>>> `SomeException`. >>>>>>>> >>>>> >>>>>>>> >>>>> * Types need to opt-in to be usable with >>>>>>>> `SomeExceptionInfo`. >>>>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>>>> acting as >>>>>>>> >>>>> such an annotation. Having a class for this allows you to >>>>>>>> ask GHCI >>>>>>>> >>>>> about all in-scope exception info types via `:info >>>>>>>> ExceptionInfo`. >>>>>>>> >>>>> >>>>>>>> >>>>> Backwards Compatibility >>>>>>>> >>>>> ======================= >>>>>>>> >>>>> >>>>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. >>>>>>>> This means >>>>>>>> >>>>> that this change could be made without breaking code: >>>>>>>> >>>>> >>>>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>>>> >>>>> >>>>>>>> >>>>> Note that consumers of this do not need to enable >>>>>>>> `-XPatternSynonyms`. >>>>>>>> >>>>> >>>>>>>> >>>>> Applications >>>>>>>> >>>>> ============ >>>>>>>> >>>>> >>>>>>>> >>>>> Callstacks >>>>>>>> >>>>> ---------- >>>>>>>> >>>>> >>>>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>>>> callstacks to >>>>>>>> >>>>> exceptions: >>>>>>>> >>>>> >>>>>>>> >>>>> newtype ExceptionCallStack = >>>>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] >>>>>>>> } >>>>>>>> >>>>> deriving Typeable >>>>>>>> >>>>> >>>>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>>>> >>>>> >>>>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>>>> >>>>> throwIOWithStack e = do >>>>>>>> >>>>> stack <- currentCallStack >>>>>>>> >>>>> if null stack >>>>>>>> >>>>> then throwIO e >>>>>>>> >>>>> else throwIO (addExceptionInfo >>>>>>>> (ExceptionCallStack stack) >>>>>>>> >>>>> e) >>>>>>>> >>>>> >>>>>>>> >>>>> I see little downside for making something like this the >>>>>>>> default >>>>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>>>> `SomeException` >>>>>>>> >>>>> would add an additional stacktrace to its annotation, much >>>>>>>> like the >>>>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>>>> >>>>> stacktraces would be associated with the exception, rather >>>>>>>> than just >>>>>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>>>> programs, or in >>>>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>>>> functioning. >>>>>>>> >>>>> >>>>>>>> >>>>> Throwing Exceptions in Handlers >>>>>>>> >>>>> ------------------------------- >>>>>>>> >>>>> >>>>>>>> >>>>> Example: >>>>>>>> >>>>> >>>>>>>> >>>>> main = >>>>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>>>> >>>>> >>>>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't >>>>>>>> see it, >>>>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a >>>>>>>> few >>>>>>>> >>>>> issues: >>>>>>>> >>>>> >>>>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>>>> yielded to >>>>>>>> >>>>> the user, then the more informative error is lost. >>>>>>>> >>>>> >>>>>>>> >>>>> 2. Callers who expect to catch the "Informative error >>>>>>>> message" won't >>>>>>>> >>>>> run their handlers for this exception type. >>>>>>>> >>>>> >>>>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to >>>>>>>> the >>>>>>>> >>>>> exception: >>>>>>>> >>>>> >>>>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>>>> >>>>> deriving Typeable >>>>>>>> >>>>> >>>>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>>>> >>>>> displayExceptionInfo fe = >>>>>>>> >>>>> "thrown while handling " ++ >>>>>>>> >>>>> displayException (unExceptionCause fe) >>>>>>>> >>>>> >>>>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>>>> >>>>> where >>>>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) >>>>>>>> -> >>>>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>>>> >>>>> where >>>>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>>>> >>>>> >>>>>>>> >>>>> This implementation of `catch` is written in a >>>>>>>> backwards-compatible >>>>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>>>> still the >>>>>>>> >>>>> one that gets rethrown. The "original" exception is recorded >>>>>>>> in the >>>>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>>>> >>>>> `__context__` attribute[3]. This was brought to my attention >>>>>>>> in a >>>>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>>>> suppress >>>>>>>> >>>>> the original exception[5]. >>>>>>>> >>>>> >>>>>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>>>> >>>>> compatibility. With the earlier example, a `catch` handler >>>>>>>> for >>>>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't >>>>>>>> the >>>>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>>>> variant of >>>>>>>> >>>>> catch which instead throws the original exception. This >>>>>>>> might be a >>>>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>>>> `finally`. >>>>>>>> >>>>> >>>>>>>> >>>>> Asynchronous Exceptions >>>>>>>> >>>>> ----------------------- >>>>>>>> >>>>> >>>>>>>> >>>>> Currently, the only reliable way to catch exceptions, >>>>>>>> ignoring async >>>>>>>> >>>>> exceptions, is to fork a new thread. This is the approach >>>>>>>> used by the >>>>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that >>>>>>>> we need >>>>>>>> >>>>> to go to such lengths due to the lack of one bit of >>>>>>>> information about >>>>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>>>> >>>>> >>>>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this >>>>>>>> doesn't enforce >>>>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>>>> exception. >>>>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>>>> exception is >>>>>>>> >>>>> synchronous or asynchronous. Here's what this would look >>>>>>>> like: >>>>>>>> >>>>> >>>>>>>> >>>>> data IsAsync = IsAsync >>>>>>>> >>>>> deriving (Typeable, Show) >>>>>>>> >>>>> >>>>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>>>>> >>>>> >>>>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>>>> >>>>> >>>>>>>> >>>>> The details of this get a bit tricky: What happens if >>>>>>>> `throwIO` is >>>>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` >>>>>>>> flag set? >>>>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>>>> interactions >>>>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>>>>>> Vries[8] >>>>>>>> >>>>> and ghc trac #2558[9]. >>>>>>>> >>>>> >>>>>>>> >>>>> Issue: fromException loses info >>>>>>>> >>>>> =============================== >>>>>>>> >>>>> >>>>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>>>> >>>>> >>>>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>>>> usually form >>>>>>>> >>>>> a prism. In other words, when `fromException` yields a >>>>>>>> `Just`, you >>>>>>>> >>>>> should get the same `SomeException` when using `toException` >>>>>>>> on that >>>>>>>> >>>>> value. >>>>>>>> >>>>> >>>>>>>> >>>>> For example, >>>>>>>> >>>>> >>>>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>>>> throwIO ex >>>>>>>> >>>>> >>>>>>>> >>>>> is equivalent to >>>>>>>> >>>>> >>>>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO >>>>>>>> ex >>>>>>>> >>>>> >>>>>>>> >>>>> However, with exception info added to just `SomeException`, >>>>>>>> and no >>>>>>>> >>>>> changes to existing `Exception` instances, this >>>>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception type >>>>>>>> get >>>>>>>> >>>>> rethrown with less information. >>>>>>>> >>>>> >>>>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as >>>>>>>> a field >>>>>>>> >>>>> to existing `Exception` instances. This would require the >>>>>>>> use of >>>>>>>> >>>>> non-default implementations of the `toException` and >>>>>>>> `fromException` >>>>>>>> >>>>> instances. >>>>>>>> >>>>> >>>>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>>>> which also >>>>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>>>> >>>>> >>>>>>>> >>>>> [1] >>>>>>>> >>>>> >>>>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>>>> >>>>> [2] >>>>>>>> >>>>> >>>>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>>>> >>>>> [4] >>>>>>>> >>>>> >>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>>>> >>>>> [5] >>>>>>>> >>>>> >>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>>>> >>>>> >>>>>>>> >>>>> _______________________________________________ >>>>>>>> >>>>> Libraries mailing list >>>>>>>> >>>>> Libraries at haskell.org >>>>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>> >>>>> >>>>>>>> >>>> >>>>>>>> >>> >>>>>>>> >> >>>>>>>> > >>>>>>>> > >>>>>>>> > _______________________________________________ >>>>>>>> > Libraries mailing list >>>>>>>> > Libraries at haskell.org >>>>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>> > >>>>>>>> >>>>>>> >>>>>>> >>>>>> >>>> >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Wed Apr 22 04:16:14 2015 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 22 Apr 2015 04:16:14 +0000 Subject: Exceptions with Context Re: Proposal: Add exception info In-Reply-To: References: Message-ID: If SomeException doesn't change, where is this extra info being packaged/passed around? Are we relying on deep magic in the RTS? On Wed, Apr 22, 2015 at 7:08 AM Carter Schonwald wrote: > no michael, Daveans proposal is that we add certain catchWithExtraInfo :: > Exception e => IO a -> (ExtraInfo -> e -> IO a ) -> IO a style operations > to the exceptions modules, for various choices of "extraInfo" > > The idea being, NO current exception codes should have to change. Nor does > SomeException need to change. > i will try to articulate my concerns about your proposed design in more > details on the other proposal thread after i've had a bit more sleep and > thought about it more > > > On Tue, Apr 21, 2015 at 11:50 PM, Michael Sloan wrote: > >> Either I am misunderstanding davean's proposal, or you are >> misunderstanding mine. Namely: >> >> * How is his proposal more extensible? His specializes it to just >> passing callstack information. >> >> * I'm not sure exactly how he proposes to change the catch. If it's >> changed to always preserve the extra exception info, then this will be a >> massive API breakage. >> >> -Michael >> >> On Tue, Apr 21, 2015 at 7:23 PM, Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> hrm, i like this proposal more, and it seems like with some fleshing >>> out it can be strictly more extensible yet backwards compatible than >>> michael's >>> >>> I'll need to mull it a bit more before I cast my vote, but this seems to >>> sketch out a design that provides the same information, but in a more >>> extensible/backwards compatible fashion (at least in a first cut of >>> thinking about it) >>> >>> (i'm splitting this into a new thread so the discussions dont get mixed >>> up) >>> >>> On Tue, Apr 21, 2015 at 9:40 PM, davean wrote: >>> >>>> So, I've had a number of issues with exceptions. This has been one of >>>> them. I don't really like this proposal as it stands though as it seems to >>>> make catch a specific exception with said extra info more difficult. >>>> >>>> This is data Control.Exception can move around on its own though, >>>> right? The problem really isn't passing it internal, we could just make a >>>> (Stack, SomeException) tuple just fine, in theory I think (I'll admit I've >>>> not actually reviewed the code, and this isn't meant as a complete proposal >>>> but more a thought experiment). The problem is code handling the data and >>>> working with old code while not losing any of the power of the current >>>> system. >>>> >>>> So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>> >>>> Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> >>>> IO a >>>> If we want access to the new information, but that's not really >>>> satisfactory. >>>> >>>> Real code regularly wants to (picking an arbitrary instance of >>>> Exception) do: catch :: IO a -> (IOError -> IO a) -> IO a >>>> only we still want new data. >>>> >>>> Now one could do something like: catch :: IO a -> (Stack -> IOError -> >>>> IO a) -> IO a >>>> but that is not very upgradable and it breaks existing code. >>>> >>>> But this is just a matter of requesting information, so one could do >>>> something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a >>>> where: data WithStack e = WithStack Stack e >>>> Or maybe one just addes: catchWithContext :: Exception e => IO a -> >>>> (Context -> e -> IO a) -> IO a >>>> Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> IO >>>> a >>>> >>>> Now existing code continues to run and we can feed our exception >>>> handlers the data they want, even when we want some specific exception >>>> instead of just any exception. >>>> >>>> Now that still leave a hole in what I want out of exceptions. We're >>>> still short of programmatic interrogating them, or even telling what the >>>> exception was if we didn't expect it! >>>> >>>> Consider AssertionFailed >>>> . >>>> Its show instance is "showsPrec _ (AssertionFailed err) = showString err", >>>> so if we print out the SomeException, we get whatever string is in >>>> AssertionFailed. Which is great if that string makes sense. But you see >>>> that on your console and its a bit baffling if it doesn't. It could even be >>>> a lie, I can make that say something that looks like its a different >>>> exception. We can use the Typeable instance so the program can tell them >>>> apart at least though. Which works as long as the exception is >>>> single-constructor, or has a well-behaved show instance. What if we come >>>> across a monstrosity like >>>> http://hackage.haskell.org/package/http-conduit-2.1.5/docs/Network-HTTP-Conduit.html#g:12 >>>> and it doesn't have a nice show instance that says which on it is? If >>>> Exception added a Data constraint we could actually pull apart these >>>> exceptions and start to make proper sense of them reliably. >>>> >>>> Once you have that there are quite a few useful things you can do with >>>> the exceptions you didn't expect. Currently you could only do them by >>>> enumerating every possible exception which of course doesn't work for the >>>> unexpected. >>>> >>>> On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan >>>> wrote: >>>> >>>>> No, this proposal is not specifically about stack traces, that is just >>>>> one of the usecases. Instead, this is about a general mechanism for >>>>> including extra information with exceptions. The core of this proposal is >>>>> still relevant even if the behavior of error / throw / throwTo / etc remain >>>>> unchanged. >>>>> >>>>> I'm not familiar with how the new dwarf stuff will interact with >>>>> throwing / displaying exceptions. It seems like this would require having >>>>> the debugger break at the throw site, and exceptions would still lack stack >>>>> traces. Having informative stack traces is quite orthogonal to having a >>>>> good place to store them. >>>>> >>>>> Note that in my original proposal text I mentioned that this is >>>>> agnostic of the particular source of the stack trace. In particular, this >>>>> could be used with a profiling stack trace, implicit callstack, or, indeed, >>>>> these traces via dwarf. >>>>> >>>>> -Michael >>>>> >>>>> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >>>>> carter.schonwald at gmail.com> wrote: >>>>> >>>>>> On a more important note: assuming ghc 7.12 has support for >>>>>> informative stack traces via dwarf by default, wouldn't that eliminate the >>>>>> need for this proposal? Namely : there perhaps should be some reasonable >>>>>> way to talk about concatting stack traces perhaps? >>>>>> >>>>>> Phrased differently: how is the info that should perhaps be in >>>>>> informative stack traces not subsuming the info of this proposal? >>>>>> >>>>>> >>>>>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>>>>> >>>>>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>>>>> locations to such functions: https://phabricator.haskell.org/D861 >>>>>>> >>>>>>> However, there are some issues with changing the API of these >>>>>>> functions: https://phabricator.haskell.org/D861#23250 >>>>>>> >>>>>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" >>>>>>> thread) >>>>>>> >>>>>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>>>>> wrote: >>>>>>> >>>>>>>> Hmm, that patch doesn't appear to add stack traces to >>>>>>>> 'Prelude.error', which is what Carter wants here. Also, I think it would >>>>>>>> be done with profiling callstacks rather than implicit callstacks. But >>>>>>>> it's certainly also useful to have functions which do the same with >>>>>>>> implicit callstacks! >>>>>>>> >>>>>>>> >>>>>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>>>>> >>>>>>>>> https://phabricator.haskell.org/D578 >>>>>>>>> >>>>>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>>>>> wrote: >>>>>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>>>>> > wrote: >>>>>>>>> >> >>>>>>>>> >> if you can patch prelude error to include stack traces, i will >>>>>>>>> owe you a >>>>>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>>>>> christmas. :) >>>>>>>>> > >>>>>>>>> > >>>>>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>>>>> Looking >>>>>>>>> > forward to ICFP beers either way :D >>>>>>>>> > >>>>>>>>> >> i can't speak for how a different patch might work out, because >>>>>>>>> thats not >>>>>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>>>>> results! >>>>>>>>> >> -Carter >>>>>>>>> >> >>>>>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan < >>>>>>>>> mgsloan at gmail.com> wrote: >>>>>>>>> >>> >>>>>>>>> >>> Hi Carter! >>>>>>>>> >>> >>>>>>>>> >>> Interesting! This thread, right? >>>>>>>>> >>> >>>>>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>>>>> >>> >>>>>>>>> >>> I haven't tried this as a patch to base, but I'm certain that >>>>>>>>> the core of >>>>>>>>> >>> the proposal has no extra dependencies. Note that the >>>>>>>>> proposal isn't about >>>>>>>>> >>> stack traces in particular - that's just one application of >>>>>>>>> being able to >>>>>>>>> >>> throw exceptions with extra information. >>>>>>>>> >>> >>>>>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with >>>>>>>>> stack traces, >>>>>>>>> >>> this functionality could be provided outside of >>>>>>>>> `Control.Exception` (though, >>>>>>>>> >>> that does seem like the right place to put it). I'm surprised >>>>>>>>> that the >>>>>>>>> >>> circularity was so problematic, though. Why isn't it >>>>>>>>> sufficient to have an >>>>>>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>>>>>> >>> >>>>>>>>> >>> -Michael >>>>>>>>> >>> >>>>>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>>>>> >>> wrote: >>>>>>>>> >>>> >>>>>>>>> >>>> Hey Michael, >>>>>>>>> >>>> I actually proposed something along these lines that got OK'd >>>>>>>>> by >>>>>>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>>>>>> actually doing >>>>>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>>>>> some nasty >>>>>>>>> >>>> module cycles in base that happen when you try to weave >>>>>>>>> things around so >>>>>>>>> >>>> that the standard error "message here" call includes some >>>>>>>>> stack trace info. >>>>>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>>>>> >>>> >>>>>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work >>>>>>>>> and just >>>>>>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>>>>>> love some >>>>>>>>> >>>> headway on that front. >>>>>>>>> >>>> >>>>>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>>>>> info data >>>>>>>>> >>>> in >7.10 to provide useful stack traces in the default builds >>>>>>>>> for GHC afaik, >>>>>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>>>>> currenlty only work >>>>>>>>> >>>> on profiled builds >>>>>>>>> >>>> >>>>>>>>> >>>> cheers >>>>>>>>> >>>> -Carter >>>>>>>>> >>>> >>>>>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>>>>> mgsloan at gmail.com> >>>>>>>>> >>>> wrote: >>>>>>>>> >>>>> >>>>>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>>>>> could be >>>>>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], >>>>>>>>> but we have >>>>>>>>> >>>>> no generic way to include this information with exceptions. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Proposed Solution >>>>>>>>> >>>>> ================= >>>>>>>>> >>>>> >>>>>>>>> >>>>> The proposed solution is to add a list of >>>>>>>>> `SomeExceptionInfo` to the >>>>>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>>>>> information >>>>>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>>>>> mechanism >>>>>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>>>>> `Exception` type >>>>>>>>> >>>>> works: >>>>>>>>> >>>>> >>>>>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>>>>> >>>>> >>>>>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>>>>> >>>>> SomeExceptionInfo a >>>>>>>>> >>>>> >>>>>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>>>>> >>>>> >>>>>>>>> >>>>> addExceptionInfo >>>>>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>>>>> >>>>> => a -> e -> SomeException >>>>>>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo >>>>>>>>> e xs) = >>>>>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>>>>> >>>>> >>>>>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that >>>>>>>>> `Exception` has, >>>>>>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>>>>>> exception >>>>>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>>>>> necessary >>>>>>>>> >>>>> casting. >>>>>>>>> >>>>> >>>>>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>>>>> constraint >>>>>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to >>>>>>>>> have a new >>>>>>>>> >>>>> class for this so that: >>>>>>>>> >>>>> >>>>>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>>>>> >>>>> implementation, for when this extra info is presented to >>>>>>>>> the user. >>>>>>>>> >>>>> This function would be invoked by the `show` >>>>>>>>> implementation for >>>>>>>>> >>>>> `SomeException`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> * Types need to opt-in to be usable with >>>>>>>>> `SomeExceptionInfo`. >>>>>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>>>>> acting as >>>>>>>>> >>>>> such an annotation. Having a class for this allows you to >>>>>>>>> ask GHCI >>>>>>>>> >>>>> about all in-scope exception info types via `:info >>>>>>>>> ExceptionInfo`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Backwards Compatibility >>>>>>>>> >>>>> ======================= >>>>>>>>> >>>>> >>>>>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. >>>>>>>>> This means >>>>>>>>> >>>>> that this change could be made without breaking code: >>>>>>>>> >>>>> >>>>>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ >>>>>>>>> where >>>>>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>>>>> >>>>> >>>>>>>>> >>>>> Note that consumers of this do not need to enable >>>>>>>>> `-XPatternSynonyms`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Applications >>>>>>>>> >>>>> ============ >>>>>>>>> >>>>> >>>>>>>>> >>>>> Callstacks >>>>>>>>> >>>>> ---------- >>>>>>>>> >>>>> >>>>>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>>>>> callstacks to >>>>>>>>> >>>>> exceptions: >>>>>>>>> >>>>> >>>>>>>>> >>>>> newtype ExceptionCallStack = >>>>>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: >>>>>>>>> [String] } >>>>>>>>> >>>>> deriving Typeable >>>>>>>>> >>>>> >>>>>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>>>>> >>>>> >>>>>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>>>>> >>>>> throwIOWithStack e = do >>>>>>>>> >>>>> stack <- currentCallStack >>>>>>>>> >>>>> if null stack >>>>>>>>> >>>>> then throwIO e >>>>>>>>> >>>>> else throwIO (addExceptionInfo >>>>>>>>> (ExceptionCallStack stack) >>>>>>>>> >>>>> e) >>>>>>>>> >>>>> >>>>>>>>> >>>>> I see little downside for making something like this the >>>>>>>>> default >>>>>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>>>>> `SomeException` >>>>>>>>> >>>>> would add an additional stacktrace to its annotation, much >>>>>>>>> like the >>>>>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>>>>> >>>>> stacktraces would be associated with the exception, rather >>>>>>>>> than just >>>>>>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>>>>> programs, or in >>>>>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>>>>> functioning. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Throwing Exceptions in Handlers >>>>>>>>> >>>>> ------------------------------- >>>>>>>>> >>>>> >>>>>>>>> >>>>> Example: >>>>>>>>> >>>>> >>>>>>>>> >>>>> main = >>>>>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>>>>> >>>>> >>>>>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't >>>>>>>>> see it, >>>>>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes >>>>>>>>> a few >>>>>>>>> >>>>> issues: >>>>>>>>> >>>>> >>>>>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>>>>> yielded to >>>>>>>>> >>>>> the user, then the more informative error is lost. >>>>>>>>> >>>>> >>>>>>>>> >>>>> 2. Callers who expect to catch the "Informative error >>>>>>>>> message" won't >>>>>>>>> >>>>> run their handlers for this exception type. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to >>>>>>>>> the >>>>>>>>> >>>>> exception: >>>>>>>>> >>>>> >>>>>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>>>>> >>>>> deriving Typeable >>>>>>>>> >>>>> >>>>>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>>>>> >>>>> displayExceptionInfo fe = >>>>>>>>> >>>>> "thrown while handling " ++ >>>>>>>>> >>>>> displayException (unExceptionCause fe) >>>>>>>>> >>>>> >>>>>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>>>>> >>>>> where >>>>>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) >>>>>>>>> -> >>>>>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>>>>> >>>>> where >>>>>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>>>>> >>>>> >>>>>>>>> >>>>> This implementation of `catch` is written in a >>>>>>>>> backwards-compatible >>>>>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>>>>> still the >>>>>>>>> >>>>> one that gets rethrown. The "original" exception is >>>>>>>>> recorded in the >>>>>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>>>>> >>>>> `__context__` attribute[3]. This was brought to my >>>>>>>>> attention in a >>>>>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>>>>> suppress >>>>>>>>> >>>>> the original exception[5]. >>>>>>>>> >>>>> >>>>>>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>>>>> >>>>> compatibility. With the earlier example, a `catch` handler >>>>>>>>> for >>>>>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't >>>>>>>>> the >>>>>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>>>>> variant of >>>>>>>>> >>>>> catch which instead throws the original exception. This >>>>>>>>> might be a >>>>>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>>>>> `finally`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Asynchronous Exceptions >>>>>>>>> >>>>> ----------------------- >>>>>>>>> >>>>> >>>>>>>>> >>>>> Currently, the only reliable way to catch exceptions, >>>>>>>>> ignoring async >>>>>>>>> >>>>> exceptions, is to fork a new thread. This is the approach >>>>>>>>> used by the >>>>>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly >>>>>>>>> that we need >>>>>>>>> >>>>> to go to such lengths due to the lack of one bit of >>>>>>>>> information about >>>>>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>>>>> >>>>> >>>>>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this >>>>>>>>> doesn't enforce >>>>>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>>>>> exception. >>>>>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>>>>> exception is >>>>>>>>> >>>>> synchronous or asynchronous. Here's what this would look >>>>>>>>> like: >>>>>>>>> >>>>> >>>>>>>>> >>>>> data IsAsync = IsAsync >>>>>>>>> >>>>> deriving (Typeable, Show) >>>>>>>>> >>>>> >>>>>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>>>>> >>>>> displayExceptionInfo IsAsync = "thrown >>>>>>>>> asynchronously" >>>>>>>>> >>>>> >>>>>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>>>>> >>>>> >>>>>>>>> >>>>> The details of this get a bit tricky: What happens if >>>>>>>>> `throwIO` is >>>>>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` >>>>>>>>> flag set? >>>>>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>>>>> interactions >>>>>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>>>>> >>>>> exceptions. Such details are explained in a post by Edsko >>>>>>>>> de Vries[8] >>>>>>>>> >>>>> and ghc trac #2558[9]. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Issue: fromException loses info >>>>>>>>> >>>>> =============================== >>>>>>>>> >>>>> >>>>>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>>>>> >>>>> >>>>>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>>>>> usually form >>>>>>>>> >>>>> a prism. In other words, when `fromException` yields a >>>>>>>>> `Just`, you >>>>>>>>> >>>>> should get the same `SomeException` when using `toException` >>>>>>>>> on that >>>>>>>>> >>>>> value. >>>>>>>>> >>>>> >>>>>>>>> >>>>> For example, >>>>>>>>> >>>>> >>>>>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>>>>> throwIO ex >>>>>>>>> >>>>> >>>>>>>>> >>>>> is equivalent to >>>>>>>>> >>>>> >>>>>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO >>>>>>>>> ex >>>>>>>>> >>>>> >>>>>>>>> >>>>> However, with exception info added to just `SomeException`, >>>>>>>>> and no >>>>>>>>> >>>>> changes to existing `Exception` instances, this >>>>>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception >>>>>>>>> type get >>>>>>>>> >>>>> rethrown with less information. >>>>>>>>> >>>>> >>>>>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as >>>>>>>>> a field >>>>>>>>> >>>>> to existing `Exception` instances. This would require the >>>>>>>>> use of >>>>>>>>> >>>>> non-default implementations of the `toException` and >>>>>>>>> `fromException` >>>>>>>>> >>>>> instances. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>>>>> which also >>>>>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> [1] >>>>>>>>> >>>>> >>>>>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>>>>> >>>>> [2] >>>>>>>>> >>>>> >>>>>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>>>>> >>>>> [4] >>>>>>>>> >>>>> >>>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>>>>> >>>>> [5] >>>>>>>>> >>>>> >>>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>>>>> >>>>> >>>>>>>>> >>>>> _______________________________________________ >>>>>>>>> >>>>> Libraries mailing list >>>>>>>>> >>>>> Libraries at haskell.org >>>>>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>>> >>>>> >>>>>>>>> >>>> >>>>>>>>> >>> >>>>>>>>> >> >>>>>>>>> > >>>>>>>>> > >>>>>>>>> > _______________________________________________ >>>>>>>>> > Libraries mailing list >>>>>>>>> > Libraries at haskell.org >>>>>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>>> > >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>> >>>>> >>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>>> >>> >> > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed Apr 22 04:16:52 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Wed, 22 Apr 2015 00:16:52 -0400 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: ..... why are you using exceptions are part of normal control flow for actions that aren't some manner of thread timeout or otherwise exceptional? on a more important note... its important to note that youre focusing on the *profiling build* notion of call stack, rather than the (still moderately in progress) dwarf stack trace work thats still on going. The stack trace spamming issue you're alluding to that arises in the +RTS -xc -RTS profiling stack traces should not ever happen with dwarf stack traces. what precludes changing all exceptions in base/userland to having proper stack traces associated with them as an alternative design that addresses that same issues. I ask this because any changes to base are only going to be happening in future GHCs, and thus any discussions about changing exceptions in base really need to be forward looking with respect to parallel materially ongoing work in GHC for those who wanna read up on whats currently afoot in stack trace land for GHC, let me share the following links https://ghc.haskell.org/trac/ghc/ticket/3693#comment:75 https://ghc.haskell.org/trac/ghc/wiki/DWARF http://arashrouhani.com/papers/master-thesis.pdf On Tue, Apr 21, 2015 at 11:43 PM, Michael Sloan wrote: > Davean's proposal is essentially the same as mine, restarted and > specialized to callstacks. So, I'm not sure why it would make you vote > against this. > > This does more than just stack traces, and is independent of the source of > call stacks. What kind of mechanism are you envisioning that would make it > redundant to include the callstack with the exception? > > I can imagine setting a thread local variable to the "last callstack of > raise#". However, this does not allow us to accumulate callstacks when the > exception is rethrown. Often you care more about the initial throw of the > exception, rather than the most recent one. > > For example, with `+GHC -xc` output, when an exception is caught and > rethrown, you'll see the callstacks of all the places it's thrown. This > output is rather terrible for real world debugging, though, because it > doesn't actually tell you what the exception is. When dealing with a > concurrent system where some exceptions occur as part of normal operation, > this becomes nightmareish. This proposal solves that problem. If you see > even the rough possibility of another solution to this problem, please do > tell. > > -Michael > > On Tue, Apr 21, 2015 at 7:26 PM, Carter Schonwald < > carter.schonwald at gmail.com> wrote: > >> in the context of davean's proposal (which i'm still digesting), i'm >> gonna go -1 on this one. >> >> i'm really leery of commiting to any changes to our exception machinery >> until the dwarf stack trace tooling and associated RTS/exception >> interaction support is a bit more mature, because i think a lot of other >> approaches / changes to ghc / base have been driven by the lack of cheap >> stack traces. This proposal crosses that line, at least for me ;) >> >> On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan wrote: >> >>> No, this proposal is not specifically about stack traces, that is just >>> one of the usecases. Instead, this is about a general mechanism for >>> including extra information with exceptions. The core of this proposal is >>> still relevant even if the behavior of error / throw / throwTo / etc remain >>> unchanged. >>> >>> I'm not familiar with how the new dwarf stuff will interact with >>> throwing / displaying exceptions. It seems like this would require having >>> the debugger break at the throw site, and exceptions would still lack stack >>> traces. Having informative stack traces is quite orthogonal to having a >>> good place to store them. >>> >>> Note that in my original proposal text I mentioned that this is agnostic >>> of the particular source of the stack trace. In particular, this could be >>> used with a profiling stack trace, implicit callstack, or, indeed, these >>> traces via dwarf. >>> >>> -Michael >>> >>> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >>> carter.schonwald at gmail.com> wrote: >>> >>>> On a more important note: assuming ghc 7.12 has support for informative >>>> stack traces via dwarf by default, wouldn't that eliminate the need for >>>> this proposal? Namely : there perhaps should be some reasonable way to talk >>>> about concatting stack traces perhaps? >>>> >>>> Phrased differently: how is the info that should perhaps be in >>>> informative stack traces not subsuming the info of this proposal? >>>> >>>> >>>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>>> >>>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>>> locations to such functions: https://phabricator.haskell.org/D861 >>>>> >>>>> However, there are some issues with changing the API of these >>>>> functions: https://phabricator.haskell.org/D861#23250 >>>>> >>>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" >>>>> thread) >>>>> >>>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>>> wrote: >>>>> >>>>>> Hmm, that patch doesn't appear to add stack traces to >>>>>> 'Prelude.error', which is what Carter wants here. Also, I think it would >>>>>> be done with profiling callstacks rather than implicit callstacks. But >>>>>> it's certainly also useful to have functions which do the same with >>>>>> implicit callstacks! >>>>>> >>>>>> >>>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>>> wrote: >>>>>> >>>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>>> >>>>>>> https://phabricator.haskell.org/D578 >>>>>>> >>>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>>> wrote: >>>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>>> > wrote: >>>>>>> >> >>>>>>> >> if you can patch prelude error to include stack traces, i will >>>>>>> owe you a >>>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>>> christmas. :) >>>>>>> > >>>>>>> > >>>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>>> Looking >>>>>>> > forward to ICFP beers either way :D >>>>>>> > >>>>>>> >> i can't speak for how a different patch might work out, because >>>>>>> thats not >>>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>>> results! >>>>>>> >> -Carter >>>>>>> >> >>>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan < >>>>>>> mgsloan at gmail.com> wrote: >>>>>>> >>> >>>>>>> >>> Hi Carter! >>>>>>> >>> >>>>>>> >>> Interesting! This thread, right? >>>>>>> >>> >>>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>>> >>> >>>>>>> >>> I haven't tried this as a patch to base, but I'm certain that >>>>>>> the core of >>>>>>> >>> the proposal has no extra dependencies. Note that the proposal >>>>>>> isn't about >>>>>>> >>> stack traces in particular - that's just one application of >>>>>>> being able to >>>>>>> >>> throw exceptions with extra information. >>>>>>> >>> >>>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>>>>> traces, >>>>>>> >>> this functionality could be provided outside of >>>>>>> `Control.Exception` (though, >>>>>>> >>> that does seem like the right place to put it). I'm surprised >>>>>>> that the >>>>>>> >>> circularity was so problematic, though. Why isn't it sufficient >>>>>>> to have an >>>>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>>>> >>> >>>>>>> >>> -Michael >>>>>>> >>> >>>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>>> >>> wrote: >>>>>>> >>>> >>>>>>> >>>> Hey Michael, >>>>>>> >>>> I actually proposed something along these lines that got OK'd by >>>>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>>>> actually doing >>>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>>> some nasty >>>>>>> >>>> module cycles in base that happen when you try to weave things >>>>>>> around so >>>>>>> >>>> that the standard error "message here" call includes some stack >>>>>>> trace info. >>>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>>> >>>> >>>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work >>>>>>> and just >>>>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>>>> love some >>>>>>> >>>> headway on that front. >>>>>>> >>>> >>>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>>> info data >>>>>>> >>>> in >7.10 to provide useful stack traces in the default builds >>>>>>> for GHC afaik, >>>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>>> currenlty only work >>>>>>> >>>> on profiled builds >>>>>>> >>>> >>>>>>> >>>> cheers >>>>>>> >>>> -Carter >>>>>>> >>>> >>>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>>> mgsloan at gmail.com> >>>>>>> >>>> wrote: >>>>>>> >>>>> >>>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>>> could be >>>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], but >>>>>>> we have >>>>>>> >>>>> no generic way to include this information with exceptions. >>>>>>> >>>>> >>>>>>> >>>>> Proposed Solution >>>>>>> >>>>> ================= >>>>>>> >>>>> >>>>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` >>>>>>> to the >>>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>>> information >>>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>>> mechanism >>>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>>> `Exception` type >>>>>>> >>>>> works: >>>>>>> >>>>> >>>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>>> >>>>> >>>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>>> >>>>> SomeExceptionInfo a >>>>>>> >>>>> >>>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>>> >>>>> >>>>>>> >>>>> addExceptionInfo >>>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>>> >>>>> => a -> e -> SomeException >>>>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo e >>>>>>> xs) = >>>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>>> >>>>> >>>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that `Exception` >>>>>>> has, >>>>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>>>> exception >>>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>>> necessary >>>>>>> >>>>> casting. >>>>>>> >>>>> >>>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>>> constraint >>>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have >>>>>>> a new >>>>>>> >>>>> class for this so that: >>>>>>> >>>>> >>>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>>> >>>>> implementation, for when this extra info is presented to the >>>>>>> user. >>>>>>> >>>>> This function would be invoked by the `show` implementation >>>>>>> for >>>>>>> >>>>> `SomeException`. >>>>>>> >>>>> >>>>>>> >>>>> * Types need to opt-in to be usable with `SomeExceptionInfo`. >>>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>>> acting as >>>>>>> >>>>> such an annotation. Having a class for this allows you to >>>>>>> ask GHCI >>>>>>> >>>>> about all in-scope exception info types via `:info >>>>>>> ExceptionInfo`. >>>>>>> >>>>> >>>>>>> >>>>> Backwards Compatibility >>>>>>> >>>>> ======================= >>>>>>> >>>>> >>>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. >>>>>>> This means >>>>>>> >>>>> that this change could be made without breaking code: >>>>>>> >>>>> >>>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>>> >>>>> >>>>>>> >>>>> Note that consumers of this do not need to enable >>>>>>> `-XPatternSynonyms`. >>>>>>> >>>>> >>>>>>> >>>>> Applications >>>>>>> >>>>> ============ >>>>>>> >>>>> >>>>>>> >>>>> Callstacks >>>>>>> >>>>> ---------- >>>>>>> >>>>> >>>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>>> callstacks to >>>>>>> >>>>> exceptions: >>>>>>> >>>>> >>>>>>> >>>>> newtype ExceptionCallStack = >>>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] } >>>>>>> >>>>> deriving Typeable >>>>>>> >>>>> >>>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>>> >>>>> >>>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>>> >>>>> throwIOWithStack e = do >>>>>>> >>>>> stack <- currentCallStack >>>>>>> >>>>> if null stack >>>>>>> >>>>> then throwIO e >>>>>>> >>>>> else throwIO (addExceptionInfo (ExceptionCallStack >>>>>>> stack) >>>>>>> >>>>> e) >>>>>>> >>>>> >>>>>>> >>>>> I see little downside for making something like this the >>>>>>> default >>>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>>> `SomeException` >>>>>>> >>>>> would add an additional stacktrace to its annotation, much >>>>>>> like the >>>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>>> >>>>> stacktraces would be associated with the exception, rather >>>>>>> than just >>>>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>>> programs, or in >>>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>>> functioning. >>>>>>> >>>>> >>>>>>> >>>>> Throwing Exceptions in Handlers >>>>>>> >>>>> ------------------------------- >>>>>>> >>>>> >>>>>>> >>>>> Example: >>>>>>> >>>>> >>>>>>> >>>>> main = >>>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>>> >>>>> >>>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't >>>>>>> see it, >>>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a >>>>>>> few >>>>>>> >>>>> issues: >>>>>>> >>>>> >>>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>>> yielded to >>>>>>> >>>>> the user, then the more informative error is lost. >>>>>>> >>>>> >>>>>>> >>>>> 2. Callers who expect to catch the "Informative error message" >>>>>>> won't >>>>>>> >>>>> run their handlers for this exception type. >>>>>>> >>>>> >>>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to the >>>>>>> >>>>> exception: >>>>>>> >>>>> >>>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>>> >>>>> deriving Typeable >>>>>>> >>>>> >>>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>>> >>>>> displayExceptionInfo fe = >>>>>>> >>>>> "thrown while handling " ++ >>>>>>> >>>>> displayException (unExceptionCause fe) >>>>>>> >>>>> >>>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>>> >>>>> where >>>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) -> >>>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>>> >>>>> where >>>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>>> >>>>> >>>>>>> >>>>> This implementation of `catch` is written in a >>>>>>> backwards-compatible >>>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>>> still the >>>>>>> >>>>> one that gets rethrown. The "original" exception is recorded >>>>>>> in the >>>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>>> >>>>> `__context__` attribute[3]. This was brought to my attention >>>>>>> in a >>>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>>> suppress >>>>>>> >>>>> the original exception[5]. >>>>>>> >>>>> >>>>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>>> >>>>> compatibility. With the earlier example, a `catch` handler for >>>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't >>>>>>> the >>>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>>> variant of >>>>>>> >>>>> catch which instead throws the original exception. This might >>>>>>> be a >>>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>>> `finally`. >>>>>>> >>>>> >>>>>>> >>>>> Asynchronous Exceptions >>>>>>> >>>>> ----------------------- >>>>>>> >>>>> >>>>>>> >>>>> Currently, the only reliable way to catch exceptions, ignoring >>>>>>> async >>>>>>> >>>>> exceptions, is to fork a new thread. This is the approach >>>>>>> used by the >>>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that >>>>>>> we need >>>>>>> >>>>> to go to such lengths due to the lack of one bit of >>>>>>> information about >>>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>>> >>>>> >>>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this doesn't >>>>>>> enforce >>>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>>> exception. >>>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>>> exception is >>>>>>> >>>>> synchronous or asynchronous. Here's what this would look like: >>>>>>> >>>>> >>>>>>> >>>>> data IsAsync = IsAsync >>>>>>> >>>>> deriving (Typeable, Show) >>>>>>> >>>>> >>>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>>>> >>>>> >>>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>>> >>>>> >>>>>>> >>>>> The details of this get a bit tricky: What happens if >>>>>>> `throwIO` is >>>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` >>>>>>> flag set? >>>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>>> interactions >>>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>>>>> Vries[8] >>>>>>> >>>>> and ghc trac #2558[9]. >>>>>>> >>>>> >>>>>>> >>>>> Issue: fromException loses info >>>>>>> >>>>> =============================== >>>>>>> >>>>> >>>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>>> >>>>> >>>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>>> usually form >>>>>>> >>>>> a prism. In other words, when `fromException` yields a >>>>>>> `Just`, you >>>>>>> >>>>> should get the same `SomeException` when using `toException` >>>>>>> on that >>>>>>> >>>>> value. >>>>>>> >>>>> >>>>>>> >>>>> For example, >>>>>>> >>>>> >>>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>>> throwIO ex >>>>>>> >>>>> >>>>>>> >>>>> is equivalent to >>>>>>> >>>>> >>>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO ex >>>>>>> >>>>> >>>>>>> >>>>> However, with exception info added to just `SomeException`, >>>>>>> and no >>>>>>> >>>>> changes to existing `Exception` instances, this >>>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception type >>>>>>> get >>>>>>> >>>>> rethrown with less information. >>>>>>> >>>>> >>>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as a >>>>>>> field >>>>>>> >>>>> to existing `Exception` instances. This would require the use >>>>>>> of >>>>>>> >>>>> non-default implementations of the `toException` and >>>>>>> `fromException` >>>>>>> >>>>> instances. >>>>>>> >>>>> >>>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>>> which also >>>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>>> >>>>> >>>>>>> >>>>> [1] >>>>>>> >>>>> >>>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>>> >>>>> [2] >>>>>>> >>>>> >>>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>>> >>>>> [4] >>>>>>> >>>>> >>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>>> >>>>> [5] >>>>>>> >>>>> >>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>>> >>>>> >>>>>>> >>>>> _______________________________________________ >>>>>>> >>>>> Libraries mailing list >>>>>>> >>>>> Libraries at haskell.org >>>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>> >>>>> >>>>>>> >>>> >>>>>>> >>> >>>>>>> >> >>>>>>> > >>>>>>> > >>>>>>> > _______________________________________________ >>>>>>> > Libraries mailing list >>>>>>> > Libraries at haskell.org >>>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>> > >>>>>>> >>>>>> >>>>>> >>>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ezyang at mit.edu Tue Apr 21 19:46:05 2015 From: ezyang at mit.edu (Edward Z. Yang) Date: Tue, 21 Apr 2015 20:46:05 +0100 Subject: Proposal: NF newtype In-Reply-To: <1423557418-sup-9734@sabre> References: <1423557418-sup-9734@sabre> Message-ID: <1429645452-sup-3608@sabre> Hello all, Taking the appropriate suggestion, I have created a small package to provide this functionality: https://hackage.haskell.org/package/nf If it migrates into deepseq, we can update this package to reexport the appropriate modules from deepseq when it is available. Please let me know if there's anything (e.g. version bounds) which I can do to make this more "enterprise" ready. Cheers, Edward Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000: > I propose the following (abstract) data type, functions, and instance be > added to deepseq (naming amenable to bikeshedding): > > newtype NF a = NF a -- abstract > makeNF :: NFData a => a -> NF a > getNF :: NF a -> a > instance NFData (NF a) where > rnf x = x `seq` () > > NF is an abstract data type representing data which has been evaluated > to normal form; the guarantee specifically is, if NF is in whnf, then > it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it > in order to assure that it is fully evaluated. > > This guarantee is sufficient for a variety of cases where > normal data is necessary, e.g. when transmitting data over Channels. > For example, from the monad-par library 'put_' could be used in place > of 'put' with this type signature. > > put_ :: IVar (NF a) -> (NF a) -> Par () > > Cheers, > Edward From michael at snoyman.com Wed Apr 22 07:54:32 2015 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 22 Apr 2015 07:54:32 +0000 Subject: Proposal: NF newtype In-Reply-To: <1429645452-sup-3608@sabre> References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> Message-ID: Small request: could you bump the upper bound to allow base 4? ;) On Wed, Apr 22, 2015 at 10:50 AM Edward Z. Yang wrote: > Hello all, > > Taking the appropriate suggestion, I have created a small > package to provide this functionality: > > https://hackage.haskell.org/package/nf > > If it migrates into deepseq, we can update this package to reexport > the appropriate modules from deepseq when it is available. > > Please let me know if there's anything (e.g. version bounds) which > I can do to make this more "enterprise" ready. > > Cheers, > Edward > > Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000: > > I propose the following (abstract) data type, functions, and instance be > > added to deepseq (naming amenable to bikeshedding): > > > > newtype NF a = NF a -- abstract > > makeNF :: NFData a => a -> NF a > > getNF :: NF a -> a > > instance NFData (NF a) where > > rnf x = x `seq` () > > > > NF is an abstract data type representing data which has been evaluated > > to normal form; the guarantee specifically is, if NF is in whnf, then > > it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it > > in order to assure that it is fully evaluated. > > > > This guarantee is sufficient for a variety of cases where > > normal data is necessary, e.g. when transmitting data over Channels. > > For example, from the monad-par library 'put_' could be used in place > > of 'put' with this type signature. > > > > put_ :: IVar (NF a) -> (NF a) -> Par () > > > > Cheers, > > Edward > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ezyang at mit.edu Wed Apr 22 08:00:40 2015 From: ezyang at mit.edu (Edward Z. Yang) Date: Wed, 22 Apr 2015 09:00:40 +0100 Subject: Proposal: NF newtype In-Reply-To: References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> Message-ID: <1429689481-sup-2618@sabre> That's what I get for guessing syntax. Fixed. Edward Excerpts from Michael Snoyman's message of 2015-04-22 08:54:32 +0100: > Small request: could you bump the upper bound to allow base 4? ;) > > On Wed, Apr 22, 2015 at 10:50 AM Edward Z. Yang wrote: > > > Hello all, > > > > Taking the appropriate suggestion, I have created a small > > package to provide this functionality: > > > > https://hackage.haskell.org/package/nf > > > > If it migrates into deepseq, we can update this package to reexport > > the appropriate modules from deepseq when it is available. > > > > Please let me know if there's anything (e.g. version bounds) which > > I can do to make this more "enterprise" ready. > > > > Cheers, > > Edward > > > > Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000: > > > I propose the following (abstract) data type, functions, and instance be > > > added to deepseq (naming amenable to bikeshedding): > > > > > > newtype NF a = NF a -- abstract > > > makeNF :: NFData a => a -> NF a > > > getNF :: NF a -> a > > > instance NFData (NF a) where > > > rnf x = x `seq` () > > > > > > NF is an abstract data type representing data which has been evaluated > > > to normal form; the guarantee specifically is, if NF is in whnf, then > > > it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it > > > in order to assure that it is fully evaluated. > > > > > > This guarantee is sufficient for a variety of cases where > > > normal data is necessary, e.g. when transmitting data over Channels. > > > For example, from the monad-par library 'put_' could be used in place > > > of 'put' with this type signature. > > > > > > put_ :: IVar (NF a) -> (NF a) -> Par () > > > > > > Cheers, > > > Edward > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > From michael at snoyman.com Wed Apr 22 08:10:44 2015 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 22 Apr 2015 08:10:44 +0000 Subject: Proposal: NF newtype In-Reply-To: <1429689481-sup-2618@sabre> References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> <1429689481-sup-2618@sabre> Message-ID: Only thing I can think of is adding a bunch of `deriving`s to NF. I can picture people wanting to just plot an `NF` into the middle of their data structures and still be able to `show` it for debugging. I'm guessing a minimal list may be Show, Read, Eq, Ord, Typeable. Data and Generic seem like an interesting case, since- on the one hand- it would be nice to have the instances (especially the latter) for auto-deriving mechanisms, but in theory it can be used to break the abstraction. However, given that you're already giving people an escape route via the .Internal module, I don't think that's as big a concern. On Wed, Apr 22, 2015 at 11:04 AM Edward Z. Yang wrote: > That's what I get for guessing syntax. Fixed. > > Edward > > Excerpts from Michael Snoyman's message of 2015-04-22 08:54:32 +0100: > > Small request: could you bump the upper bound to allow base 4? ;) > > > > On Wed, Apr 22, 2015 at 10:50 AM Edward Z. Yang wrote: > > > > > Hello all, > > > > > > Taking the appropriate suggestion, I have created a small > > > package to provide this functionality: > > > > > > https://hackage.haskell.org/package/nf > > > > > > If it migrates into deepseq, we can update this package to reexport > > > the appropriate modules from deepseq when it is available. > > > > > > Please let me know if there's anything (e.g. version bounds) which > > > I can do to make this more "enterprise" ready. > > > > > > Cheers, > > > Edward > > > > > > Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000: > > > > I propose the following (abstract) data type, functions, and > instance be > > > > added to deepseq (naming amenable to bikeshedding): > > > > > > > > newtype NF a = NF a -- abstract > > > > makeNF :: NFData a => a -> NF a > > > > getNF :: NF a -> a > > > > instance NFData (NF a) where > > > > rnf x = x `seq` () > > > > > > > > NF is an abstract data type representing data which has been > evaluated > > > > to normal form; the guarantee specifically is, if NF is in whnf, then > > > > it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it > > > > in order to assure that it is fully evaluated. > > > > > > > > This guarantee is sufficient for a variety of cases where > > > > normal data is necessary, e.g. when transmitting data over Channels. > > > > For example, from the monad-par library 'put_' could be used in place > > > > of 'put' with this type signature. > > > > > > > > put_ :: IVar (NF a) -> (NF a) -> Par () > > > > > > > > Cheers, > > > > Edward > > > _______________________________________________ > > > Libraries mailing list > > > Libraries at haskell.org > > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From danburton.email at gmail.com Wed Apr 22 18:45:34 2015 From: danburton.email at gmail.com (Dan Burton) Date: Wed, 22 Apr 2015 11:45:34 -0700 Subject: Proposal: NF newtype In-Reply-To: References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> <1429689481-sup-2618@sabre> Message-ID: A hand-written read makes more sense to me in this case: read = makeNF . read show = show . getNF Other instances where a "new value" is created can be written similarly: instance (Monoid m) => Monoid (NF m) where mempty = makeNF mempty mappend aNF bNF = makeNF (mappend (getNF aNF) (getNF bNF)) Whether the pattern of using NF this way is a good idea... I don't know. It just seems nice if data of type `NF a` can be used as a drop-in replacement for data of type `a`. -- Dan Burton On Wed, Apr 22, 2015 at 1:10 AM, Michael Snoyman wrote: > Only thing I can think of is adding a bunch of `deriving`s to NF. I can > picture people wanting to just plot an `NF` into the middle of their data > structures and still be able to `show` it for debugging. I'm guessing a > minimal list may be Show, Read, Eq, Ord, Typeable. Data and Generic seem > like an interesting case, since- on the one hand- it would be nice to have > the instances (especially the latter) for auto-deriving mechanisms, but in > theory it can be used to break the abstraction. However, given that you're > already giving people an escape route via the .Internal module, I don't > think that's as big a concern. > > On Wed, Apr 22, 2015 at 11:04 AM Edward Z. Yang wrote: > >> That's what I get for guessing syntax. Fixed. >> >> Edward >> >> Excerpts from Michael Snoyman's message of 2015-04-22 08:54:32 +0100: >> > Small request: could you bump the upper bound to allow base 4? ;) >> > >> > On Wed, Apr 22, 2015 at 10:50 AM Edward Z. Yang wrote: >> > >> > > Hello all, >> > > >> > > Taking the appropriate suggestion, I have created a small >> > > package to provide this functionality: >> > > >> > > https://hackage.haskell.org/package/nf >> > > >> > > If it migrates into deepseq, we can update this package to reexport >> > > the appropriate modules from deepseq when it is available. >> > > >> > > Please let me know if there's anything (e.g. version bounds) which >> > > I can do to make this more "enterprise" ready. >> > > >> > > Cheers, >> > > Edward >> > > >> > > Excerpts from Edward Z. Yang's message of 2015-02-10 08:46:37 +0000: >> > > > I propose the following (abstract) data type, functions, and >> instance be >> > > > added to deepseq (naming amenable to bikeshedding): >> > > > >> > > > newtype NF a = NF a -- abstract >> > > > makeNF :: NFData a => a -> NF a >> > > > getNF :: NF a -> a >> > > > instance NFData (NF a) where >> > > > rnf x = x `seq` () >> > > > >> > > > NF is an abstract data type representing data which has been >> evaluated >> > > > to normal form; the guarantee specifically is, if NF is in whnf, >> then >> > > > it is in nf. Crucially, when we have 'NF a', we ONLY need to seq it >> > > > in order to assure that it is fully evaluated. >> > > > >> > > > This guarantee is sufficient for a variety of cases where >> > > > normal data is necessary, e.g. when transmitting data over Channels. >> > > > For example, from the monad-par library 'put_' could be used in >> place >> > > > of 'put' with this type signature. >> > > > >> > > > put_ :: IVar (NF a) -> (NF a) -> Par () >> > > > >> > > > Cheers, >> > > > Edward >> > > _______________________________________________ >> > > Libraries mailing list >> > > Libraries at haskell.org >> > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > > >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Wed Apr 22 18:49:56 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Wed, 22 Apr 2015 20:49:56 +0200 (CEST) Subject: Proposal: NF newtype In-Reply-To: References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> <1429689481-sup-2618@sabre> Message-ID: On Wed, 22 Apr 2015, Dan Burton wrote: > A hand-written read makes more sense to me in this case: > read = makeNF . read > show = show . getNF Show and Read instances should process Strings representing Haskell code, and I guess, Haskell code with the same type as the represented value. Thus the NF should be part of the formatted value. From ezyang at mit.edu Wed Apr 22 18:54:21 2015 From: ezyang at mit.edu (Edward Z. Yang) Date: Wed, 22 Apr 2015 19:54:21 +0100 Subject: Proposal: NF newtype In-Reply-To: References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> <1429689481-sup-2618@sabre> Message-ID: <1429728818-sup-3383@sabre> But it is an interesting question whether or not 'UnsafeNF' should be used, since the value read in is known to be in normal form. Edward Excerpts from Henning Thielemann's message of 2015-04-22 19:49:56 +0100: > > On Wed, 22 Apr 2015, Dan Burton wrote: > > > A hand-written read makes more sense to me in this case: > > read = makeNF . read > > show = show . getNF > > Show and Read instances should process Strings representing Haskell code, > and I guess, Haskell code with the same type as the represented value. > Thus the NF should be part of the formatted value. From roma at ro-che.info Wed Apr 22 20:28:10 2015 From: roma at ro-che.info (Roman Cheplyaka) Date: Wed, 22 Apr 2015 23:28:10 +0300 Subject: Proposal: NF newtype In-Reply-To: <1429728818-sup-3383@sabre> References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> <1429689481-sup-2618@sabre> <1429728818-sup-3383@sabre> Message-ID: <5538045A.6020602@ro-che.info> On 22/04/15 21:54, Edward Z. Yang wrote: > But it is an interesting question whether or not 'UnsafeNF' should be > used, since the value read in is known to be in normal form. Is it? newtype X = X Int deriving Show instance Read X where readsPrec n = map (first $ X . trace "eval") . readsPrec n > length (read "[1,2,3]" :: [X]) 3 > read "[1,2,3]" :: [X] [X eval 1,X eval 2,X eval 3] Or did you mean something else? > Excerpts from Henning Thielemann's message of 2015-04-22 19:49:56 +0100: >> >> On Wed, 22 Apr 2015, Dan Burton wrote: >> >>> A hand-written read makes more sense to me in this case: >>> read = makeNF . read >>> show = show . getNF >> >> Show and Read instances should process Strings representing Haskell code, >> and I guess, Haskell code with the same type as the represented value. >> Thus the NF should be part of the formatted value. > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > From ezyang at mit.edu Wed Apr 22 20:38:34 2015 From: ezyang at mit.edu (Edward Z. Yang) Date: Wed, 22 Apr 2015 21:38:34 +0100 Subject: Proposal: NF newtype In-Reply-To: <5538045A.6020602@ro-che.info> References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> <1429689481-sup-2618@sabre> <1429728818-sup-3383@sabre> <5538045A.6020602@ro-che.info> Message-ID: <1429735107-sup-9193@sabre> OK, perhaps not :) Edward Excerpts from Roman Cheplyaka's message of 2015-04-22 21:28:10 +0100: > On 22/04/15 21:54, Edward Z. Yang wrote: > > But it is an interesting question whether or not 'UnsafeNF' should be > > used, since the value read in is known to be in normal form. > > Is it? > > newtype X = X Int > deriving Show > instance Read X where > readsPrec n = map (first $ X . trace "eval") . readsPrec n > > > length (read "[1,2,3]" :: [X]) > 3 > > read "[1,2,3]" :: [X] > [X eval > 1,X eval > 2,X eval > 3] > > Or did you mean something else? > > > Excerpts from Henning Thielemann's message of 2015-04-22 19:49:56 +0100: > >> > >> On Wed, 22 Apr 2015, Dan Burton wrote: > >> > >>> A hand-written read makes more sense to me in this case: > >>> read = makeNF . read > >>> show = show . getNF > >> > >> Show and Read instances should process Strings representing Haskell code, > >> and I guess, Haskell code with the same type as the represented value. > >> Thus the NF should be part of the formatted value. > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > From gale at sefer.org Thu Apr 23 09:02:45 2015 From: gale at sefer.org (Yitzchak Gale) Date: Thu, 23 Apr 2015 12:02:45 +0300 Subject: Proposal: Add exception info In-Reply-To: <5536A05D.5@gmail.com> References: <5536A05D.5@gmail.com> Message-ID: I wrote: >> Package foo uploads a new version with a critical bug fix. >> As is often the case, this new version also supports updated >> dependencies, including exceptions. The new exceptions >> breaks the old SomeException type, so foo is forced to >> specify a lower bound that excludes the old exceptions. Michael Snoyman wrote: >> I'm not seeing a situation where an author couldn't easily >> be compatible with GHC <=7.8 by sticking to the >> old API? Felipe Lessa wrote: > I think Michael Gale heh > is thinking about an author that may end up using the new > SomeExceptionWithInfo constructor for some reason, thus > leaving older GHCs out of any new updates. Right, exactly what I was thinking. But perhaps Michael Sn. is correct that explicit use of a SomeException constructor is rare. (Which is what I think is what he means by "sticking to the old API".) If that is really true, then my objection is not valid. And I'm certainly strongly in favor of the goals of this proposal. So I'd be in favor even if *some* breakage results from it, as long as the overall deprecation curve isn't unreasonably steep. Thanks, Yitz From gale at sefer.org Thu Apr 23 09:15:17 2015 From: gale at sefer.org (Yitzchak Gale) Date: Thu, 23 Apr 2015 12:15:17 +0300 Subject: Proposal: NF newtype In-Reply-To: References: <1423557418-sup-9734@sabre> <1429645452-sup-3608@sabre> <1429689481-sup-2618@sabre> Message-ID: Henning Thielemann wrote: > Show and Read instances should process Strings representing Haskell code, > and I guess, Haskell code with the same type as the represented value. Thus > the NF should be part of the formatted value. Agreed. Instead, add stand-alone functions: readNF = makeNF . read showNF = show . getNF From michael at snoyman.com Thu Apr 23 13:15:44 2015 From: michael at snoyman.com (Michael Snoyman) Date: Thu, 23 Apr 2015 13:15:44 +0000 Subject: Proposal: Add exception info In-Reply-To: References: <5536A05D.5@gmail.com> Message-ID: On Thu, Apr 23, 2015 at 12:03 PM Yitzchak Gale wrote: > I wrote: > >> Package foo uploads a new version with a critical bug fix. > >> As is often the case, this new version also supports updated > >> dependencies, including exceptions. The new exceptions > >> breaks the old SomeException type, so foo is forced to > >> specify a lower bound that excludes the old exceptions. > > Michael Snoyman wrote: > >> I'm not seeing a situation where an author couldn't easily > >> be compatible with GHC <=7.8 by sticking to the > >> old API? > > Felipe Lessa wrote: > > I think Michael Gale > > heh > > > is thinking about an author that may end up using the new > > SomeExceptionWithInfo constructor for some reason, thus > > leaving older GHCs out of any new updates. > > Right, exactly what I was thinking. But perhaps > Michael Sn. is correct that explicit use of a SomeException > constructor is rare. (Which is what I think is what he means by > "sticking to the old API".) If that is really true, then my objection > is not valid. > > And I'm certainly strongly in favor of the goals of this > proposal. So I'd be in favor even if *some* breakage > results from it, as long as the overall deprecation curve > isn't unreasonably steep. > > Thanks, > Yitz > > Maybe we're on the same page, but just to be sure, I'd like to clarify: with Michael Sloan's proposal, you can still explicitly use the SomeException constructor. Under GHC <=7.10 it's just a normal data constructor. Under GHC >=7.12 it would be this pattern synonym thing (I really haven't looked into the extension yet). Meaning that anything you could do with GHC 7.10 and earlier could still be done with 7.12 without any breakage. Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg at gregweber.info Thu Apr 23 13:30:26 2015 From: greg at gregweber.info (Greg Weber) Date: Thu, 23 Apr 2015 06:30:26 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Tue, Apr 21, 2015 at 1:55 PM, Michael Sloan wrote: > > On Tue, Apr 21, 2015 at 8:23 AM, Greg Weber wrote: > >> >> On Tue, Apr 14, 2015 at 11:38 AM, Michael Sloan >> wrote: >> >>> data SomeException = forall e . Exception e => >>> SomeExceptionWithInfo e [SomeExceptionInfo] >>> >>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>> SomeExceptionInfo a >> >> >> Is it necessary for SomeExceptionWithInfo to have a list of a forall data >> type? >> Are Exceptions really that mysterious, or can we more concretely describe >> the information that should be attached to an exception? >> >> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >> > > I did consider this option, but I think as soon as a fixed set is > selected, someone's going to put something else in it. Usually we wouldn't > want to use such a 'dynamic' mechanism in Haskell, but it's appropriate for > something so global as the type used to throw exceptions. > The usual approach is to use information hiding. We are being rescued by pattern synonyms right now because the constructor is directly exported. Why not hide what needs to be hidden to make this more extensible and use smart constructors, etc?. > > >> I am still open to the idea of adding a forall data scratchpad, but can >> we at least try to specify some standard fields? >> >> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >> [SomeExceptionInfo] >> > > This is an interesting idea. I particularly see value in having 'IsAsync' > be a part of the Exception. This is because `throwIO` / `throw` would need > to set this to False when rethrowing async exceptions. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nikita.y.volkov at mail.ru Thu Apr 23 16:02:32 2015 From: nikita.y.volkov at mail.ru (Nikita Volkov) Date: Thu, 23 Apr 2015 19:02:32 +0300 Subject: Applicative instance of ExceptT is wrong Message-ID: I've recently discovered a flaw in the Applicative and Alternative instances of EitherT. I've posted the following pull request to fix them: https://github.com/ekmett/either/pull/38 The pull request contains the description of the problem. ExceptT of "transformers" contains exactly the same flaw. However it's not hosted on GitHub, so I don't know a better place to report the issue then here. Best regards, Nikita Volkov -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Thu Apr 23 18:39:29 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Thu, 23 Apr 2015 20:39:29 +0200 (CEST) Subject: Applicative instance of ExceptT is wrong In-Reply-To: References: Message-ID: On Thu, 23 Apr 2015, Nikita Volkov wrote: > ExceptT of "transformers" contains exactly the same flaw. However it's > not hosted on GitHub, so I don't know a better place to report the issue > then here. http://hub.darcs.net/ross/transformers/issues From ekmett at gmail.com Thu Apr 23 19:07:12 2015 From: ekmett at gmail.com (Edward Kmett) Date: Thu, 23 Apr 2015 15:07:12 -0400 Subject: Applicative instance of ExceptT is wrong In-Reply-To: References: Message-ID: https://mail.haskell.org/pipermail/libraries/2015-January/024633.html This has been raised before and rejected as it doesn't work. The `Applicative` instance for `EitherT e m` does not have the same semantics as the Applicative for `Compose m (Either e)`. Consider foo <*> bar foo = EitherT $ return $ Left "nope" bar = throw "die die die" If you foo 'fails', yielding Left e then EitherT e m a _stops_. It doesn't run the next action. On the other hand, `Compose m (Either e)` will run both foo and bar, then merge the answers. This is observably different if bar fails in a stronger way. e.g. if m itself is something like IO you can throw an exception in bar. The EitherT e IO instance will never execute bar, and never throw that exception. These are different Applicatives for different types. This issue has been repeatedly raised against transformers (at least once by me, once by David Feuer), and Ross has patiently corrected us each time. I figure it is my turn to pass along the received wisdom. ;) The instance you request is only valid when 'm' has no notion of failure of its own, or no notion of observable side-effects. It doesn't work for m = IO. It doesn't work for m = Either f. In essence it isn't a valid instance for a Monad _transformer_, but rather it is only a valid instance for particular, well behaved, monads. -Edward On Thu, Apr 23, 2015 at 12:02 PM, Nikita Volkov wrote: > I've recently discovered a flaw in the Applicative and Alternative > instances of EitherT. I've posted the following pull request to fix them: > > https://github.com/ekmett/either/pull/38 > > The pull request contains the description of the problem. > > ExceptT of "transformers" contains exactly the same flaw. However it's not > hosted on GitHub, so I don't know a better place to report the issue then > here. > > Best regards, > Nikita Volkov > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From shumovichy at gmail.com Fri Apr 24 12:29:53 2015 From: shumovichy at gmail.com (Yuras Shumovich) Date: Fri, 24 Apr 2015 15:29:53 +0300 Subject: Export ($!) from Data.Function Message-ID: <1429878593.2806.12.camel@gmail.com> Hello, Right now ($!) operator can be imported either from Prelude or GHC.Base. The later is specific to GHC, so it makes sense to avoid it. There are reasons to avoid Prelude too (e.g. because it pollutes name space, changes too often, etc.) We need a home module for all identifies from Prelude, so that one can import them without importing Prelude. Data.Functor seems to be a good candidate for ($!) operator home module. It already exports ($) operator. Thanks, Yuras From ivan.miljenovic at gmail.com Fri Apr 24 12:56:36 2015 From: ivan.miljenovic at gmail.com (Ivan Lazar Miljenovic) Date: Fri, 24 Apr 2015 22:56:36 +1000 Subject: Export ($!) from Data.Function In-Reply-To: <1429878593.2806.12.camel@gmail.com> References: <1429878593.2806.12.camel@gmail.com> Message-ID: On 24 April 2015 at 22:29, Yuras Shumovich wrote: > > Hello, > > Right now ($!) operator can be imported either from Prelude or GHC.Base. > The later is specific to GHC, so it makes sense to avoid it. > > There are reasons to avoid Prelude too (e.g. because it pollutes name > space, changes too often, etc.) We need a home module for all identifies > from Prelude, so that one can import them without importing Prelude. > > Data.Functor seems to be a good candidate for ($!) operator home module. > It already exports ($) operator. Except $! is already exported by Prelude, so it's likely to break code by removing it from there. > > Thanks, > Yuras > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -- Ivan Lazar Miljenovic Ivan.Miljenovic at gmail.com http://IvanMiljenovic.wordpress.com From ivan.miljenovic at gmail.com Fri Apr 24 13:06:07 2015 From: ivan.miljenovic at gmail.com (Ivan Lazar Miljenovic) Date: Fri, 24 Apr 2015 23:06:07 +1000 Subject: Ord for partially ordered sets Message-ID: What is the validity of defining an Ord instance for types for which mathematically the `compare` function is partially ordered? Specifically, I have a pull request for fgl [1] to add Ord instances for the graph types (based upon the Ord instances for Data.Map and Data.IntMap, which I believe are themselves partially ordered), and I'm torn as to the soundness of adding these instances. It might be useful in Haskell code (the example given is to use graphs as keys in a Map) but mathematically-speaking it is not possible to compare two arbitrary graphs. What are people's thoughts on this? What's more important: potential usefulness/practicality or mathematical correctness? (Of course, the correct answer is to have a function of type a -> a -> Maybe Ordering :p) [1]: https://github.com/haskell/fgl/pull/11 -- Ivan Lazar Miljenovic Ivan.Miljenovic at gmail.com http://IvanMiljenovic.wordpress.com From shumovichy at gmail.com Fri Apr 24 13:06:36 2015 From: shumovichy at gmail.com (Yuras Shumovich) Date: Fri, 24 Apr 2015 16:06:36 +0300 Subject: Export ($!) from Data.Function In-Reply-To: References: <1429878593.2806.12.camel@gmail.com> Message-ID: <1429880796.2806.16.camel@gmail.com> On Fri, 2015-04-24 at 22:56 +1000, Ivan Lazar Miljenovic wrote: > On 24 April 2015 at 22:29, Yuras Shumovich wrote: > > > > Hello, > > > > Right now ($!) operator can be imported either from Prelude or GHC.Base. > > The later is specific to GHC, so it makes sense to avoid it. > > > > There are reasons to avoid Prelude too (e.g. because it pollutes name > > space, changes too often, etc.) We need a home module for all identifies > > from Prelude, so that one can import them without importing Prelude. > > > > Data.Functor seems to be a good candidate for ($!) operator home module. > > It already exports ($) operator. > > Except $! is already exported by Prelude, so it's likely to break code > by removing it from there. I propose to export ($!) from Data.Function. I don't propose to remove it from Prelude. Just like ($) is already exported from both Prelude and Data.Function. PS: sorry, I typed Data.Functor in the initial email body. The correct module name is Data.Function. > > > > > Thanks, > > Yuras > > > > > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > From tom-lists-haskell-cafe-2013 at jaguarpaw.co.uk Fri Apr 24 13:17:04 2015 From: tom-lists-haskell-cafe-2013 at jaguarpaw.co.uk (Tom Ellis) Date: Fri, 24 Apr 2015 14:17:04 +0100 Subject: [Haskell-cafe] Ord for partially ordered sets In-Reply-To: References: Message-ID: <20150424131704.GK27512@weber> On Fri, Apr 24, 2015 at 11:06:07PM +1000, Ivan Lazar Miljenovic wrote: > What is the validity of defining an Ord instance for types for which > mathematically the `compare` function is partially ordered? I'm confused. What is supposed to be the result of `g1 <= g2` when `g1` and `g2` are not comparable according to the partial order? From ivan.miljenovic at gmail.com Fri Apr 24 13:27:46 2015 From: ivan.miljenovic at gmail.com (Ivan Lazar Miljenovic) Date: Fri, 24 Apr 2015 23:27:46 +1000 Subject: [Haskell-cafe] Ord for partially ordered sets In-Reply-To: <20150424131704.GK27512@weber> References: <20150424131704.GK27512@weber> Message-ID: On 24 April 2015 at 23:17, Tom Ellis wrote: > On Fri, Apr 24, 2015 at 11:06:07PM +1000, Ivan Lazar Miljenovic wrote: >> What is the validity of defining an Ord instance for types for which >> mathematically the `compare` function is partially ordered? > > I'm confused. What is supposed to be the result of `g1 <= g2` when `g1` and > `g2` are not comparable according to the partial order? With the proposed patch, it's the result of <= on the underlying [Int]Maps. Does the definition of Ord on Data.Map make sense? e.g. what should be the result of (fromList [(1,'a'), (2,'b'), (3, 'c')]) <= (fromList [(1,'a'), (4,'d')])? What about (fromList [(1,'a'), (2,'b'), (3, 'c')]) <= (fromList [(1,'a'), (2,'e')])? -- Ivan Lazar Miljenovic Ivan.Miljenovic at gmail.com http://IvanMiljenovic.wordpress.com From lemming at henning-thielemann.de Fri Apr 24 13:51:13 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Fri, 24 Apr 2015 15:51:13 +0200 (CEST) Subject: Export ($!) from Data.Function In-Reply-To: <1429878593.2806.12.camel@gmail.com> References: <1429878593.2806.12.camel@gmail.com> Message-ID: On Fri, 24 Apr 2015, Yuras Shumovich wrote: > Right now ($!) operator can be imported either from Prelude or GHC.Base. > The later is specific to GHC, so it makes sense to avoid it. > > There are reasons to avoid Prelude too (e.g. because it pollutes name > space, changes too often, etc.) We need a home module for all identifies > from Prelude, so that one can import them without importing Prelude. I don't understand. If you don't like to import it, you can import Prelude hiding (($!)) If you have disabled automatic import of Prelude, you can still import it selectively by: import Prelude (($!)) > Data.Functor seems to be a good candidate for ($!) operator home module. > It already exports ($) operator. I think it would better fit in a module for 'seq' and friends. Unfortunately there is no such module yet. From tom-lists-haskell-cafe-2013 at jaguarpaw.co.uk Fri Apr 24 13:59:37 2015 From: tom-lists-haskell-cafe-2013 at jaguarpaw.co.uk (Tom Ellis) Date: Fri, 24 Apr 2015 14:59:37 +0100 Subject: [Haskell-cafe] Ord for partially ordered sets In-Reply-To: References: <20150424131704.GK27512@weber> Message-ID: <20150424135937.GL27512@weber> On Fri, Apr 24, 2015 at 11:27:46PM +1000, Ivan Lazar Miljenovic wrote: > On 24 April 2015 at 23:17, Tom Ellis > wrote: > > On Fri, Apr 24, 2015 at 11:06:07PM +1000, Ivan Lazar Miljenovic wrote: > >> What is the validity of defining an Ord instance for types for which > >> mathematically the `compare` function is partially ordered? > > > > I'm confused. What is supposed to be the result of `g1 <= g2` when `g1` and > > `g2` are not comparable according to the partial order? > > With the proposed patch, it's the result of <= on the underlying [Int]Maps. Ah, so it's a case of adding a valid Ord instance that isn't a natural one for the particular datatype. If you really need something like that, for example to add your graphs to a Data.Set, then I would suggest a newtype might be appropriate. Tom From lemming at henning-thielemann.de Fri Apr 24 14:01:31 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Fri, 24 Apr 2015 16:01:31 +0200 (CEST) Subject: Ord for partially ordered sets In-Reply-To: References: Message-ID: On Fri, 24 Apr 2015, Ivan Lazar Miljenovic wrote: > Specifically, I have a pull request for fgl [1] to add Ord instances for > the graph types (based upon the Ord instances for Data.Map and > Data.IntMap, which I believe are themselves partially ordered), and I'm > torn as to the soundness of adding these instances. In an application we needed to do some combinatorics of graphs and thus needed Set Graph. Nonetheless, I think that graph0 < graph1 should be a type error. We can still have a set of Graphs using a newtype. From david.feuer at gmail.com Fri Apr 24 14:09:07 2015 From: david.feuer at gmail.com (David Feuer) Date: Fri, 24 Apr 2015 10:09:07 -0400 Subject: Export ($!) from Data.Function In-Reply-To: References: <1429878593.2806.12.camel@gmail.com> Message-ID: Agreed. I think it would be nice to gather up seq-things and par-things into a nice piece of module hierarchy in some fashion. I make no claim to know how to do so nicely. On Fri, Apr 24, 2015 at 9:51 AM, Henning Thielemann < lemming at henning-thielemann.de> wrote: > > On Fri, 24 Apr 2015, Yuras Shumovich wrote: > > Right now ($!) operator can be imported either from Prelude or GHC.Base. >> The later is specific to GHC, so it makes sense to avoid it. >> >> There are reasons to avoid Prelude too (e.g. because it pollutes name >> space, changes too often, etc.) We need a home module for all identifies >> from Prelude, so that one can import them without importing Prelude. >> > > I don't understand. If you don't like to import it, you can > import Prelude hiding (($!)) > > If you have disabled automatic import of Prelude, you can still import it > selectively by: > import Prelude (($!)) > > > Data.Functor seems to be a good candidate for ($!) operator home module. >> It already exports ($) operator. >> > > I think it would better fit in a module for 'seq' and friends. > Unfortunately there is no such module yet. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From shumovichy at gmail.com Fri Apr 24 14:18:45 2015 From: shumovichy at gmail.com (Yuras Shumovich) Date: Fri, 24 Apr 2015 17:18:45 +0300 Subject: Export ($!) from Data.Function In-Reply-To: References: <1429878593.2806.12.camel@gmail.com> Message-ID: <1429885125.2806.22.camel@gmail.com> On Fri, 2015-04-24 at 15:51 +0200, Henning Thielemann wrote: > On Fri, 24 Apr 2015, Yuras Shumovich wrote: > > > Right now ($!) operator can be imported either from Prelude or GHC.Base. > > The later is specific to GHC, so it makes sense to avoid it. > > > > There are reasons to avoid Prelude too (e.g. because it pollutes name > > space, changes too often, etc.) We need a home module for all identifies > > from Prelude, so that one can import them without importing Prelude. > > I don't understand. If you don't like to import it, you can > import Prelude hiding (($!)) > > If you have disabled automatic import of Prelude, you can still import it > selectively by: > import Prelude (($!)) That is what I'm doing right now. It is too noisy because there is a number of identifiers that live only in Prelude: error, undefined, seq, etc. I believe they should eventually get their homes too. > > > > Data.Functor seems to be a good candidate for ($!) operator home module. > > It already exports ($) operator. > > I think it would better fit in a module for 'seq' and friends. > Unfortunately there is no such module yet. My argument for Data.Function was to unify it with ($), but Data.Evaluate or something similar is OK for me too. Thanks, Yuras. From ivan.miljenovic at gmail.com Fri Apr 24 14:23:42 2015 From: ivan.miljenovic at gmail.com (Ivan Lazar Miljenovic) Date: Sat, 25 Apr 2015 00:23:42 +1000 Subject: Ord for partially ordered sets In-Reply-To: References: Message-ID: On 25 April 2015 at 00:01, Henning Thielemann wrote: > > On Fri, 24 Apr 2015, Ivan Lazar Miljenovic wrote: > >> Specifically, I have a pull request for fgl [1] to add Ord instances for >> the graph types (based upon the Ord instances for Data.Map and Data.IntMap, >> which I believe are themselves partially ordered), and I'm torn as to the >> soundness of adding these instances. > > > In an application we needed to do some combinatorics of graphs and thus > needed Set Graph. > > Nonetheless, I think that graph0 < graph1 should be a type error. We can > still have a set of Graphs using a newtype. This could work; the possible problem would be one of efficiency: if it's done directly on the graph datatypes they can use the underlying (ordered) data structure; going purely by the Graph API, there's no guarantees of ordering and thus it would be needed to call sort, even though in practice it's redundant. -- Ivan Lazar Miljenovic Ivan.Miljenovic at gmail.com http://IvanMiljenovic.wordpress.com From andreas.abel at ifi.lmu.de Fri Apr 24 14:47:50 2015 From: andreas.abel at ifi.lmu.de (Andreas Abel) Date: Fri, 24 Apr 2015 16:47:50 +0200 Subject: Ord for partially ordered sets In-Reply-To: References: Message-ID: <553A5796.2020804@ifi.lmu.de> On 04/24/2015 03:06 PM, Ivan Lazar Miljenovic wrote: > What is the validity of defining an Ord instance for types for which > mathematically the `compare` function is partially ordered? I'd say this is harmful, as functions like min and max (and others) rely on the totality of the ordering. Partial orderings are useful in itself, I implemented my own library https://hackage.haskell.org/package/Agda-2.4.2/docs/Agda-Utils-PartialOrd.html mainly to use it for maintaining sets of incomparable elements: https://hackage.haskell.org/package/Agda-2.4.2/docs/Agda-Utils-Favorites.html > Specifically, I have a pull request for fgl [1] to add Ord instances > for the graph types (based upon the Ord instances for Data.Map and > Data.IntMap, which I believe are themselves partially ordered), and > I'm torn as to the soundness of adding these instances. It might be > useful in Haskell code (the example given is to use graphs as keys in > a Map) but mathematically-speaking it is not possible to compare two > arbitrary graphs. > > What are people's thoughts on this? What's more important: potential > usefulness/practicality or mathematical correctness? > > (Of course, the correct answer is to have a function of type a -> a -> > Maybe Ordering :p) > > [1]: https://github.com/haskell/fgl/pull/11 > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From tikhon at jelv.is Fri Apr 24 17:26:42 2015 From: tikhon at jelv.is (Tikhon Jelvis) Date: Fri, 24 Apr 2015 10:26:42 -0700 Subject: Ord for partially ordered sets In-Reply-To: <553A5796.2020804@ifi.lmu.de> References: <553A5796.2020804@ifi.lmu.de> Message-ID: I would be hesitant about adding an Ord instance normally, because there's no clear semantics for it. If we just pass it through to the underlying data structure, it might behave differently depending on how you implement the graph, which is something fgl should ideally abstract over. Maybe you could provide them in a newtype yourself, in the library? You could call it something like GrKey to make it clear that it has an Ord instance for practical reasons rather than because graphs are meaningfully orderable. This just forces people who need the capability to be a bit more explicit about it. On Fri, Apr 24, 2015 at 7:47 AM, Andreas Abel wrote: > On 04/24/2015 03:06 PM, Ivan Lazar Miljenovic wrote: > >> What is the validity of defining an Ord instance for types for which >> mathematically the `compare` function is partially ordered? >> > > I'd say this is harmful, as functions like min and max (and others) rely > on the totality of the ordering. > > Partial orderings are useful in itself, I implemented my own library > > > > https://hackage.haskell.org/package/Agda-2.4.2/docs/Agda-Utils-PartialOrd.html > > mainly to use it for maintaining sets of incomparable elements: > > > > https://hackage.haskell.org/package/Agda-2.4.2/docs/Agda-Utils-Favorites.html > > Specifically, I have a pull request for fgl [1] to add Ord instances >> for the graph types (based upon the Ord instances for Data.Map and >> Data.IntMap, which I believe are themselves partially ordered), and >> I'm torn as to the soundness of adding these instances. It might be >> useful in Haskell code (the example given is to use graphs as keys in >> a Map) but mathematically-speaking it is not possible to compare two >> arbitrary graphs. >> >> What are people's thoughts on this? What's more important: potential >> usefulness/practicality or mathematical correctness? >> >> (Of course, the correct answer is to have a function of type a -> a -> >> Maybe Ordering :p) >> >> [1]: https://github.com/haskell/fgl/pull/11 >> >> > > -- > Andreas Abel <>< Du bist der geliebte Mensch. > > Department of Computer Science and Engineering > Chalmers and Gothenburg University, Sweden > > andreas.abel at gu.se > http://www2.tcs.ifi.lmu.de/~abel/ > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jays at panix.com Fri Apr 24 19:26:00 2015 From: jays at panix.com (Jay Sulzberger) Date: Fri, 24 Apr 2015 15:26:00 -0400 (EDT) Subject: [Haskell-cafe] Ord for partially ordered sets (fwd) Message-ID: On Fri, 24 Apr 2015, Ivan Lazar Miljenovic wrote: > What is the validity of defining an Ord instance for types for which > mathematically the `compare` function is partially ordered? > > Specifically, I have a pull request for fgl [1] to add Ord instances > for the graph types (based upon the Ord instances for Data.Map and > Data.IntMap, which I believe are themselves partially ordered), and > I'm torn as to the soundness of adding these instances. It might be > useful in Haskell code (the example given is to use graphs as keys in > a Map) but mathematically-speaking it is not possible to compare two > arbitrary graphs. > > What are people's thoughts on this? What's more important: potential > usefulness/practicality or mathematical correctness? > > (Of course, the correct answer is to have a function of type a -> a -> > Maybe Ordering :p) > > [1]: https://github.com/haskell/fgl/pull/11 > > -- > Ivan Lazar Miljenovic Of course these type-classes (I hope I am using the word correctly) should be standard: 1. Ord, which is the class of all totally ordered set-like things 2. PoSet, which is the class of all partially ordered set-like things 3. NonStrictPoSet, which is the class of all partially ordered set-like things, but without the requirement that a <= b and b <= a implies a Equal b. 4. Things like above, but with the requirement of a Zero, with the requirement of a One, and the requirement fo both a Zero and a One. oo--JS. > Ivan.Miljenovic at gmail.com > http://IvanMiljenovic.wordpress.com > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > > From mike at izbicki.me Fri Apr 24 23:39:20 2015 From: mike at izbicki.me (Mike Izbicki) Date: Fri, 24 Apr 2015 16:39:20 -0700 Subject: [Haskell-cafe] Ord for partially ordered sets In-Reply-To: References: <20150424131704.GK27512@weber> Message-ID: >> I'm confused. What is supposed to be the result of `g1 <= g2` when `g1` and >> `g2` are not comparable according to the partial order? > >False. The operators aren't a problem for this reason. The real problem is what does `compare` return? On Fri, Apr 24, 2015 at 1:32 PM, Ertugrul S?ylemez wrote: >> I'm confused. What is supposed to be the result of `g1 <= g2` when `g1` and >> `g2` are not comparable according to the partial order? > > False. > > > Greets, > Ertugrul > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > From carter.schonwald at gmail.com Sat Apr 25 01:56:44 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Fri, 24 Apr 2015 21:56:44 -0400 Subject: [Haskell-cafe] Class-like features for explicit arguments (was: Ord for partially ordered sets) In-Reply-To: References: Message-ID: hrm, wouldn't your proposed extension be largely accomplished by using Record pun and Record WildCards? eg {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecordPuns #-} module Foo where data Relation a = Rel{related :: a -> a ->Bool,unrelated :: a -> a -> Bool} foo :: Relation A -> A -> A -> Bool foo Rel{..} x y = related x y ------ or am i over looking something? I do realize this may not quite be what youre suggesting, and if so, could you help me understand better? :) On Fri, Apr 24, 2015 at 4:26 PM, Ertugrul S?ylemez wrote: > > 3. NonStrictPoSet, which is the class of all partially ordered > > set-like things, but without the requirement that a <= b and b <= a > > implies a Equal b. > > Those are preorders. An antisymmetric preorder is a non-strict poset. > > Also it's difficult to capture all of those various order types in > Haskell's class system. A type can have many orders and many underlying > equivalence relations in the case of partial and total orders, and there > are different ways to combine them. For example equality is a partial > order, modular equivalence is a preorder, etc. Those denote bags and > groups more than sequences or trees. > > Perhaps it's time to add a type class-like system to Haskell, but for > explicitly passed arguments: > > record Relation a where > related :: a -> a -> Bool > > unrelated :: a -> a -> Bool > unrelated x y = not (related x y) > > func1 :: Relation A -> A -> A -> A > func1 _ x y = ... related x y ... > > func2 :: Relation A -> Relation A -> A -> A -> A > func2 r1 r2 x y = ... r1.related x y ... r2.unrelated x y ... > > In a lot of cases this is much more appropriate than a type class, and > it would turn many things that are currently types into regular > functions, thus making them a lot more composable: > > down :: Ord a -> Ord a > down o = > Ord { compare x y = o.compare y x } > -- The remaining Ord functions are defaulted. > > Perhaps all we need is to generalise default definitions to data types > and add module-like dot syntax for records (mainly to preserve infix > operators). Formally speaking there is also little that prevents us > From having associated types in those records that can be used on the > type level. > > For actual record types (i.e. single-constructor types) we could even > have specialisation and get a nice performance boost that way, if we ask > for it: > > {-# SPECIALISE down someOrder :: Ord SomeType #-} > > This would be extremely useful. > > > > 4. Things like above, but with the requirement of a Zero, with the > > requirement of a One, and the requirement fo both a Zero and a One. > > Zero and one as in minBound and maxBound or rather as in Monoid and a > hypothetical Semiring? In the latter case I believe they don't really > belong into an additional class, unless you have some ordering-related > laws for the zeroes and ones. If not, you can always simply use an > Ord+Semiring constraint. > > There may be some motivation to make Bounded a subclass of Ord though. > > > Greets, > Ertugrul > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From roma at ro-che.info Sat Apr 25 14:24:37 2015 From: roma at ro-che.info (Roman Cheplyaka) Date: Sat, 25 Apr 2015 17:24:37 +0300 Subject: [Haskell-cafe] Class-like features for explicit arguments In-Reply-To: References: Message-ID: <553BA3A5.6060608@ro-che.info> On 25/04/15 15:51, Ertugrul S?ylemez wrote: >> hrm, wouldn't your proposed extension be largely accomplished by using >> Record pun and Record WildCards? > > A part of it would, but it wouldn't preserve operators. For example > instead of `x r.<> y` you would have to write `(<>) r x y`. Not at all. {-# LANGUAGE RecordWildCards #-} import Prelude hiding (sum) data Monoid a = Monoid { empty :: a, (<>) :: a -> a -> a } sum :: Num a => Monoid a sum = Monoid 0 (+) three :: Integer three = let Monoid{..} = sum in 1 <> 2 > Other class features are not accessible, > most notably type-level features like associated types. Associated types become additional type variables of the record type. A class class C a where type T a is essentially equivalent to class C a t | a -> t But the functional dependency is not enforceable on the value level (isn't the whole point of this discussion not to restrict what "instances" can be defined), so you end up with class C a t, a simple MPTC. > Also defaults are not available. Now this is a good point. > The idea is that a record would be completely equivalent to a class with > the only difference being that you define values instead of instances, > that there are no constraints on which values can exist and that those > values must be passed explicitly to functions as regular arguments. Except we already have regular records (aka data types) which satisfy 90% of the requirements, and adding another language construct to satisfy those remaining 10% feels wrong to me. I'd rather improve the existing construct. Roman -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From carter.schonwald at gmail.com Sat Apr 25 15:32:43 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Sat, 25 Apr 2015 11:32:43 -0400 Subject: [Haskell-cafe] Class-like features for explicit arguments In-Reply-To: References: <553BA3A5.6060608@ro-che.info> Message-ID: Isn't your associated type here more like a dependent record field/ existential that we can kinda expose? This does seem to veer into first class module territory. Especially wrt needing first class types in a fashion. Have you had a chance to peruse the Andreas Rossberg 1ml paper on embedding first class modules into f omega that has been circulating? Perhaps there are ideas There that could be adapted. Especially since core is an augmented f omega On Saturday, April 25, 2015, Ertugrul S?ylemez wrote: > >>> hrm, wouldn't your proposed extension be largely accomplished by > >>> using Record pun and Record WildCards? > >> > >> A part of it would, but it wouldn't preserve operators. For example > >> instead of `x r.<> y` you would have to write `(<>) r x y`. > > > > Not at all. > > > > three :: Integer > > three = > > let Monoid{..} = sum in > > 1 <> 2 > > Puns become tedious and error-prone as soon as you need to refer to > multiple records, when operators are involved. But it's not that > important actually. I can live with the current record syntax. > > The most useful features would be defaults, a more suitable syntax for > defining record types and potentially the following: > > > >> Other class features are not accessible, most notably type-level > >> features like associated types. > > > > Associated types become additional type variables of the record type. > > Indeed. However, when the type follows from other type arguments, it > would often be convenient not to spell it out and instead bring an > associated type constructor into scope. This is especially true when > the AT refers to a type that isn't used very often. > > record Extractor a where > type Elem a > extract :: a -> Maybe (Elem a, a) > > extractTwo > :: (e1 : Extractor a) > -> (e2 : Extractor a) > -> a > -> Maybe (e1.Elem a, e2.Elem a, a) > extractTwo e1 e2 xs0 = do > (x1, xs1) <- e1.extract xs0 > (x2, xs2) <- e1.extract xs1 > return (x1, x2, xs2) > > > > But the functional dependency is not enforceable on the value level > > (isn't the whole point of this discussion not to restrict what > > "instances" can be defined), so you end up with > > > > class C a t, > > > > a simple MPTC. > > I don't see a reason to enforce a dependency, since there is no > equivalent to instance resolution. Regular unification should cover any > ambiguities, and if it doesn't you need ScopedTypeVariables. > > > >> The idea is that a record would be completely equivalent to a class > >> with the only difference being that you define values instead of > >> instances, that there are no constraints on which values can exist > >> and that those values must be passed explicitly to functions as > >> regular arguments. > > > > Except we already have regular records (aka data types) which satisfy > > 90% of the requirements, and adding another language construct to > > satisfy those remaining 10% feels wrong to me. I'd rather improve the > > existing construct. > > That's actually what I'm proposing. The record syntax would simply be > syntactic sugar for single-constructor data types that is more suitable > for records, especially when defaults and other class-like features are > involved. Most notably it would support layout. There is no reason why > you shouldn't be able to use `data` to achieve the same thing, except > with a clumsier syntax and the option to have multiple constructors. > > > Greets, > Ertugrul > -------------- next part -------------- An HTML attachment was scrubbed... URL: From winterkoninkje at gmail.com Sun Apr 26 01:10:15 2015 From: winterkoninkje at gmail.com (wren romano) Date: Sat, 25 Apr 2015 21:10:15 -0400 Subject: Ord for partially ordered sets In-Reply-To: References: Message-ID: On Fri, Apr 24, 2015 at 9:06 AM, Ivan Lazar Miljenovic wrote: > What is the validity of defining an Ord instance for types for which > mathematically the `compare` function is partially ordered? Defining Ord instances for types which are not totally ordered is *wrong*. For example, due to the existence of NaN values, Double/Float are not totally ordered and therefore their Ord instances are buggy. In my logfloat package I have to explicitly add checks to work around the issues introduced by the buggy Ord Double instance. This is why I introduced the PartialOrd class, and I'm not the first one to create such a class. We really ought to have an official PartialOrd class as part of base/Prelude. The only question is whether to use Maybe Ordering or a specially defined PartialOrdering type (the latter optimizing for space and pointer indirection; the former optimizing for reducing code duplication for manipulating the Ordering/PartialOrdering types). -- Live well, ~wren From oleg.grenrus at iki.fi Sun Apr 26 13:52:45 2015 From: oleg.grenrus at iki.fi (Oleg Grenrus) Date: Sun, 26 Apr 2015 16:52:45 +0300 Subject: Maintainship of edit-distance and lattices Message-ID: <0A070966-4476-4A82-A16C-65C692D9DA50@iki.fi> Hi, I?d like to help with maintaining of mentioned packages: - http://hackage.haskell.org/package/edit-distance - http://hackage.haskell.org/package/lattices Max doesn?t seem to be active on GitHub, there are - a PR to edit-distance fixing the build on GHC 7.10, open for 26 days: https://github.com/batterseapower/edit-distance/pull/3 - a PR to lattices opened at Jan 8 2015 (open for over 3 months already) https://github.com/batterseapower/lattices/pull/3 I could take over the maintainership of the packages, if Max doesn?t respond in two weeks - Oleg Grenrus -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 842 bytes Desc: Message signed with OpenPGP using GPGMail URL: From sean.leather at gmail.com Sun Apr 26 15:50:52 2015 From: sean.leather at gmail.com (Sean Leather) Date: Sun, 26 Apr 2015 17:50:52 +0200 Subject: Maintainship of edit-distance and lattices In-Reply-To: <0A070966-4476-4A82-A16C-65C692D9DA50@iki.fi> References: <0A070966-4476-4A82-A16C-65C692D9DA50@iki.fi> Message-ID: Hi Oleg, On Sun, Apr 26, 2015 at 3:52 PM, Oleg Grenrus wrote: > I?d like to help with maintaining of mentioned packages: > - http://hackage.haskell.org/package/edit-distance > - http://hackage.haskell.org/package/lattices > > Max doesn?t seem to be active on GitHub, there are > - a PR to edit-distance fixing the build on GHC 7.10, open for 26 days: > https://github.com/batterseapower/edit-distance/pull/3 > I have a pull request open for over a year. It was minor, so I didn't follow up on it: https://github.com/batterseapower/edit-distance/pull/2 - a PR to lattices opened at Jan 8 2015 (open for over 3 months already) > https://github.com/batterseapower/lattices/pull/3 > > I could take over the maintainership of the packages, if Max doesn?t > respond in two weeks > There have been other, similar requests to Max within the last 2 years or so, and I don't think there were any responses. I would be in favor of somebody else taking over as maintainer. Regards, Sean -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam at bergmark.nl Sun Apr 26 17:06:48 2015 From: adam at bergmark.nl (Adam Bergmark) Date: Sun, 26 Apr 2015 19:06:48 +0200 Subject: Maintainship of edit-distance and lattices In-Reply-To: References: <0A070966-4476-4A82-A16C-65C692D9DA50@iki.fi> Message-ID: Hi Oleg, edit-distance is also being tracked here: https://github.com/haskell-infra/hackage-trustees/issues/19 Please update it with a link to this discussion. You can also open a new issue for lattices so we can keep track of the progress for it as well. On Sun, Apr 26, 2015 at 5:50 PM, Sean Leather wrote: > Hi Oleg, > > On Sun, Apr 26, 2015 at 3:52 PM, Oleg Grenrus wrote: > >> I?d like to help with maintaining of mentioned packages: >> - http://hackage.haskell.org/package/edit-distance >> - http://hackage.haskell.org/package/lattices >> >> Max doesn?t seem to be active on GitHub, there are >> - a PR to edit-distance fixing the build on GHC 7.10, open for 26 days: >> https://github.com/batterseapower/edit-distance/pull/3 >> > > I have a pull request open for over a year. It was minor, so I didn't > follow up on it: > https://github.com/batterseapower/edit-distance/pull/2 > > - a PR to lattices opened at Jan 8 2015 (open for over 3 months already) >> https://github.com/batterseapower/lattices/pull/3 >> >> I could take over the maintainership of the packages, if Max doesn?t >> respond in two weeks >> > > There have been other, similar requests to Max within the last 2 years or > so, and I don't think there were any responses. I would be in favor of > somebody else taking over as maintainer. > > Regards, > Sean > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg.grenrus at iki.fi Sun Apr 26 17:22:56 2015 From: oleg.grenrus at iki.fi (Oleg Grenrus) Date: Sun, 26 Apr 2015 20:22:56 +0300 Subject: Maintainship of edit-distance and lattices In-Reply-To: References: <0A070966-4476-4A82-A16C-65C692D9DA50@iki.fi> Message-ID: <440AF82D-A958-4927-9F63-F4A634F10581@iki.fi> Opened a trustee issue: https://github.com/haskell-infra/hackage-trustees/issues/31 I have no hurry with lattices, as it compiles with 7.10 ok. - Oleg > On 26 Apr 2015, at 20:06, Adam Bergmark wrote: > > Hi Oleg, > > edit-distance is also being tracked here: https://github.com/haskell-infra/hackage-trustees/issues/19 > Please update it with a link to this discussion. > > You can also open a new issue for lattices so we can keep track of the progress for it as well. > > > On Sun, Apr 26, 2015 at 5:50 PM, Sean Leather > wrote: > Hi Oleg, > > On Sun, Apr 26, 2015 at 3:52 PM, Oleg Grenrus wrote: > I?d like to help with maintaining of mentioned packages: > - http://hackage.haskell.org/package/edit-distance > - http://hackage.haskell.org/package/lattices > > Max doesn?t seem to be active on GitHub, there are > - a PR to edit-distance fixing the build on GHC 7.10, open for 26 days: https://github.com/batterseapower/edit-distance/pull/3 > > I have a pull request open for over a year. It was minor, so I didn't follow up on it: > https://github.com/batterseapower/edit-distance/pull/2 > > - a PR to lattices opened at Jan 8 2015 (open for over 3 months already) https://github.com/batterseapower/lattices/pull/3 > > I could take over the maintainership of the packages, if Max doesn?t respond in two weeks > > There have been other, similar requests to Max within the last 2 years or so, and I don't think there were any responses. I would be in favor of somebody else taking over as maintainer. > > Regards, > Sean > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 842 bytes Desc: Message signed with OpenPGP using GPGMail URL: From davean at xkcd.com Sun Apr 26 18:19:20 2015 From: davean at xkcd.com (davean) Date: Sun, 26 Apr 2015 14:19:20 -0400 Subject: Maintainship of edit-distance and lattices In-Reply-To: <440AF82D-A958-4927-9F63-F4A634F10581@iki.fi> References: <0A070966-4476-4A82-A16C-65C692D9DA50@iki.fi> <440AF82D-A958-4927-9F63-F4A634F10581@iki.fi> Message-ID: I use http://hackage.haskell.org/package/lattices heavily so I care what becomes of it, but haven't had issues with it. I too have noticed he's not around though with his other packages. On Sun, Apr 26, 2015 at 1:22 PM, Oleg Grenrus wrote: > Opened a trustee issue: > > https://github.com/haskell-infra/hackage-trustees/issues/31 > > I have no hurry with lattices, as it compiles with 7.10 ok. > > - Oleg > > On 26 Apr 2015, at 20:06, Adam Bergmark wrote: > > Hi Oleg, > > edit-distance is also being tracked here: > https://github.com/haskell-infra/hackage-trustees/issues/19 > Please update it with a link to this discussion. > > You can also open a new issue for lattices so we can keep track of the > progress for it as well. > > > On Sun, Apr 26, 2015 at 5:50 PM, Sean Leather > wrote: > >> Hi Oleg, >> >> On Sun, Apr 26, 2015 at 3:52 PM, Oleg Grenrus wrote: >> >>> I?d like to help with maintaining of mentioned packages: >>> - http://hackage.haskell.org/package/edit-distance >>> - http://hackage.haskell.org/package/lattices >>> >>> Max doesn?t seem to be active on GitHub, there are >>> - a PR to edit-distance fixing the build on GHC 7.10, open for 26 days: >>> https://github.com/batterseapower/edit-distance/pull/3 >>> >> >> I have a pull request open for over a year. It was minor, so I didn't >> follow up on it: >> https://github.com/batterseapower/edit-distance/pull/2 >> >> - a PR to lattices opened at Jan 8 2015 (open for over 3 months already) >>> https://github.com/batterseapower/lattices/pull/3 >>> >>> I could take over the maintainership of the packages, if Max doesn?t >>> respond in two weeks >>> >> >> There have been other, similar requests to Max within the last 2 years or >> so, and I don't think there were any responses. I would be in favor of >> somebody else taking over as maintainer. >> >> Regards, >> Sean >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Sun Apr 26 20:26:46 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Sun, 26 Apr 2015 13:26:46 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Right, we have a choice between making a breaking change towards a more standard API, or using a rather new language extension (bidirectional pattern synonyms) to avoid breakage. On Thu, Apr 23, 2015 at 6:30 AM, Greg Weber wrote: > > > On Tue, Apr 21, 2015 at 1:55 PM, Michael Sloan wrote: > >> >> On Tue, Apr 21, 2015 at 8:23 AM, Greg Weber wrote: >> >>> >>> On Tue, Apr 14, 2015 at 11:38 AM, Michael Sloan >>> wrote: >>> >>>> data SomeException = forall e . Exception e => >>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>> >>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>> SomeExceptionInfo a >>> >>> >>> Is it necessary for SomeExceptionWithInfo to have a list of a forall >>> data type? >>> Are Exceptions really that mysterious, or can we more concretely >>> describe the information that should be attached to an exception? >>> >>> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >>> >> >> I did consider this option, but I think as soon as a fixed set is >> selected, someone's going to put something else in it. Usually we wouldn't >> want to use such a 'dynamic' mechanism in Haskell, but it's appropriate for >> something so global as the type used to throw exceptions. >> > > The usual approach is to use information hiding. We are being rescued by > pattern synonyms right now because the constructor is directly exported. > Why not hide what needs to be hidden to make this more extensible and use > smart constructors, etc?. > > >> >> >>> I am still open to the idea of adding a forall data scratchpad, but can >>> we at least try to specify some standard fields? >>> >>> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >>> [SomeExceptionInfo] >>> >> >> This is an interesting idea. I particularly see value in having >> 'IsAsync' be a part of the Exception. This is because `throwIO` / `throw` >> would need to set this to False when rethrowing async exceptions. >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sun Apr 26 21:37:52 2015 From: ekmett at gmail.com (Edward Kmett) Date: Sun, 26 Apr 2015 17:37:52 -0400 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: I have to confess that I don't really like this proposal in its current form. We use a little bit of Typeable magic in SomeException to model an open sum type. It is more or less "just enough" to get us an open set of exceptions on which we can match. That gives us a nice case analysis construction, we can basically reason type by type and ask if SomeException _is_ a particular data type without losing any information. Theoretically it means I can give you a nice prism or case handler for it, match on it, rethrow it and nothing is lost. This proposal gives up a very nice property in exchange for an ad hoc ability to decorate exceptions with anything we want. This strikes me as a short term gain in exchange for giving up a lot of future reasoning power. What is your exception decorated with? Go spend O(n) time rummaging through the list of attached decorations to find out! =/ I'm not offering a concrete worked solution, but there are many other points in this design space. e.g. having a class to let you attach the particular information you want to particular exceptions, having an exception type you can throw with a stack intact that acts as an exception transformer, etc. None of those require us to give up the simplicity of the open exceptions, but those first two obvious directions have obvious drawbacks, hence why "I'm not offering a concrete worked solution." Davean's variant narrows the focus down considerably. Limiting it to just the issue at hand, rather than trying to construct a solution to all sorts of problems we haven't even thought of yet. I could get behind something with a more retrenched scope, like that. That said, I'd very much rather err on the side of doing nothing rather than do the wrong thing here. We'll be stuck with it for a long time. -Edward On Sun, Apr 26, 2015 at 4:26 PM, Michael Sloan wrote: > Right, we have a choice between making a breaking change towards a more > standard API, or using a rather new language extension (bidirectional > pattern synonyms) to avoid breakage. > > On Thu, Apr 23, 2015 at 6:30 AM, Greg Weber wrote: > >> >> >> On Tue, Apr 21, 2015 at 1:55 PM, Michael Sloan wrote: >> >>> >>> On Tue, Apr 21, 2015 at 8:23 AM, Greg Weber wrote: >>> >>>> >>>> On Tue, Apr 14, 2015 at 11:38 AM, Michael Sloan >>>> wrote: >>>> >>>>> data SomeException = forall e . Exception e => >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>> SomeExceptionInfo a >>>> >>>> >>>> Is it necessary for SomeExceptionWithInfo to have a list of a forall >>>> data type? >>>> Are Exceptions really that mysterious, or can we more concretely >>>> describe the information that should be attached to an exception? >>>> >>>> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >>>> >>> >>> I did consider this option, but I think as soon as a fixed set is >>> selected, someone's going to put something else in it. Usually we wouldn't >>> want to use such a 'dynamic' mechanism in Haskell, but it's appropriate for >>> something so global as the type used to throw exceptions. >>> >> >> The usual approach is to use information hiding. We are being rescued by >> pattern synonyms right now because the constructor is directly exported. >> Why not hide what needs to be hidden to make this more extensible and use >> smart constructors, etc?. >> >> >>> >>> >>>> I am still open to the idea of adding a forall data scratchpad, but can >>>> we at least try to specify some standard fields? >>>> >>>> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >>>> [SomeExceptionInfo] >>>> >>> >>> This is an interesting idea. I particularly see value in having >>> 'IsAsync' be a part of the Exception. This is because `throwIO` / `throw` >>> would need to set this to False when rethrowing async exceptions. >>> >> >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Sun Apr 26 22:49:00 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Sun, 26 Apr 2015 15:49:00 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Sorry for the response delay! I wanted to take some time to review your links. On Tue, Apr 21, 2015 at 9:16 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > ..... why are you using exceptions are part of normal control flow for > actions that aren't some manner of thread timeout or otherwise exceptional? > Fair point! Personally, I think it's fine to use exceptions for circumstances in which exceptions are expected to occur. In my case, a concrete example is a network library which throws exceptions when attempting to receive / send to a connection which has disconnected. So, we expect exceptions from that. The argument could be made that this is an API design flaw. on a more important note... its important to note that youre focusing on > the *profiling build* notion of call stack, rather than the (still > moderately in progress) dwarf stack trace work thats still on going. The > stack trace spamming issue you're alluding to that arises in the +RTS -xc > -RTS profiling stack traces should not ever happen with dwarf stack traces. > I think the mechanism needs to be able to support different sources for stack traces. Since it should work for all thrown exceptions, this means adopting a global configuration of throwing with stack traces. This might look like having a function 'setRaiseFunction :: (SomeException -> IO ()) -> IO ()', which would work similarly to 'setUncaughtExceptionHandler' ( http://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Conc-Sync.html#v:setUncaughtExceptionHandler). Instead of setting the default exception handler, it sets how exceptions are thrown. This will allow the user to use profiling stack traces, DWARF stack traces, or no stack traces at all. Sure, global state like this is gross and non Haskell-ey. It's quite sensible, though, as which source of callstack being viable is a global property of your program (whether it was built with -prof, with -g for dwarf stack traces). We cannot just settle on dwarf callstacks, because that won't work for windows. what precludes changing all exceptions in base/userland to having proper > stack traces associated with them as an alternative design that addresses > that same issues. I ask this because any changes to base are only going to > be happening in future GHCs, and thus any discussions about changing > exceptions in base really need to be forward looking with respect to > parallel materially ongoing work in GHC > > for those who wanna read up on whats currently afoot in stack trace land > for GHC, let me share the following links > > https://ghc.haskell.org/trac/ghc/ticket/3693#comment:75 > https://ghc.haskell.org/trac/ghc/wiki/DWARF > http://arashrouhani.com/papers/master-thesis.pdf > I read chapter 6 of the thesis. Cool stuff, very pertinent! Our reasoning agrees a lot in section 6.3. The difference is that I'm willing to accept information being lost when catching more specific types. We could certainly pick a richer stack type than [String], such as his stack datatypes, but -prof based stack traces would also need to provide this richer type. He also explores some options involving RTS changes. These would make "execution inside a handler" into a special execution context. At the beginning of a handler, 'recoverExecutionStack' would get the stack. This alone is pretty reasonable, but there are problems with the scheme for rethrowing. The idea is essentially to modify the meaning of 'throw' within a handler to use the stack for the original exception. Section 6.3 covers a number of issues with this approach. In particular, to me the following make this seem quite undesirable: 1) Rethrowing outside the handler does not rethrow with the stack (e.g., after a try) 2) Any exception thrown in the handler gets rethrown with the original exception's callstack. This is bizarre and misleading. 3) We don't get additional stacks for the rethrows. So, unfortunately, that particular solution is also unsatisfying. It seems to me like we're pretty much trapped by the old API. So, if my proposal is distasteful, the only way forward is to break the backwards compatibility of Control.Exception, and endure propagating the API change through all the packages (leading to yucky CPP). -Michael > On Tue, Apr 21, 2015 at 11:43 PM, Michael Sloan wrote: > >> Davean's proposal is essentially the same as mine, restarted and >> specialized to callstacks. So, I'm not sure why it would make you vote >> against this. >> >> This does more than just stack traces, and is independent of the source >> of call stacks. What kind of mechanism are you envisioning that would make >> it redundant to include the callstack with the exception? >> >> I can imagine setting a thread local variable to the "last callstack of >> raise#". However, this does not allow us to accumulate callstacks when the >> exception is rethrown. Often you care more about the initial throw of the >> exception, rather than the most recent one. >> >> For example, with `+GHC -xc` output, when an exception is caught and >> rethrown, you'll see the callstacks of all the places it's thrown. This >> output is rather terrible for real world debugging, though, because it >> doesn't actually tell you what the exception is. When dealing with a >> concurrent system where some exceptions occur as part of normal operation, >> this becomes nightmareish. This proposal solves that problem. If you see >> even the rough possibility of another solution to this problem, please do >> tell. >> >> -Michael >> >> On Tue, Apr 21, 2015 at 7:26 PM, Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> in the context of davean's proposal (which i'm still digesting), i'm >>> gonna go -1 on this one. >>> >>> i'm really leery of commiting to any changes to our exception machinery >>> until the dwarf stack trace tooling and associated RTS/exception >>> interaction support is a bit more mature, because i think a lot of other >>> approaches / changes to ghc / base have been driven by the lack of cheap >>> stack traces. This proposal crosses that line, at least for me ;) >>> >>> On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan >>> wrote: >>> >>>> No, this proposal is not specifically about stack traces, that is just >>>> one of the usecases. Instead, this is about a general mechanism for >>>> including extra information with exceptions. The core of this proposal is >>>> still relevant even if the behavior of error / throw / throwTo / etc remain >>>> unchanged. >>>> >>>> I'm not familiar with how the new dwarf stuff will interact with >>>> throwing / displaying exceptions. It seems like this would require having >>>> the debugger break at the throw site, and exceptions would still lack stack >>>> traces. Having informative stack traces is quite orthogonal to having a >>>> good place to store them. >>>> >>>> Note that in my original proposal text I mentioned that this is >>>> agnostic of the particular source of the stack trace. In particular, this >>>> could be used with a profiling stack trace, implicit callstack, or, indeed, >>>> these traces via dwarf. >>>> >>>> -Michael >>>> >>>> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >>>> carter.schonwald at gmail.com> wrote: >>>> >>>>> On a more important note: assuming ghc 7.12 has support for >>>>> informative stack traces via dwarf by default, wouldn't that eliminate the >>>>> need for this proposal? Namely : there perhaps should be some reasonable >>>>> way to talk about concatting stack traces perhaps? >>>>> >>>>> Phrased differently: how is the info that should perhaps be in >>>>> informative stack traces not subsuming the info of this proposal? >>>>> >>>>> >>>>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>>>> >>>>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>>>> locations to such functions: https://phabricator.haskell.org/D861 >>>>>> >>>>>> However, there are some issues with changing the API of these >>>>>> functions: https://phabricator.haskell.org/D861#23250 >>>>>> >>>>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" >>>>>> thread) >>>>>> >>>>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>>>> wrote: >>>>>> >>>>>>> Hmm, that patch doesn't appear to add stack traces to >>>>>>> 'Prelude.error', which is what Carter wants here. Also, I think it would >>>>>>> be done with profiling callstacks rather than implicit callstacks. But >>>>>>> it's certainly also useful to have functions which do the same with >>>>>>> implicit callstacks! >>>>>>> >>>>>>> >>>>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>>>> wrote: >>>>>>> >>>>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>>>> >>>>>>>> https://phabricator.haskell.org/D578 >>>>>>>> >>>>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>>>> wrote: >>>>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>>>> > wrote: >>>>>>>> >> >>>>>>>> >> if you can patch prelude error to include stack traces, i will >>>>>>>> owe you a >>>>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>>>> christmas. :) >>>>>>>> > >>>>>>>> > >>>>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>>>> Looking >>>>>>>> > forward to ICFP beers either way :D >>>>>>>> > >>>>>>>> >> i can't speak for how a different patch might work out, because >>>>>>>> thats not >>>>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>>>> results! >>>>>>>> >> -Carter >>>>>>>> >> >>>>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan < >>>>>>>> mgsloan at gmail.com> wrote: >>>>>>>> >>> >>>>>>>> >>> Hi Carter! >>>>>>>> >>> >>>>>>>> >>> Interesting! This thread, right? >>>>>>>> >>> >>>>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>>>> >>> >>>>>>>> >>> I haven't tried this as a patch to base, but I'm certain that >>>>>>>> the core of >>>>>>>> >>> the proposal has no extra dependencies. Note that the proposal >>>>>>>> isn't about >>>>>>>> >>> stack traces in particular - that's just one application of >>>>>>>> being able to >>>>>>>> >>> throw exceptions with extra information. >>>>>>>> >>> >>>>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with stack >>>>>>>> traces, >>>>>>>> >>> this functionality could be provided outside of >>>>>>>> `Control.Exception` (though, >>>>>>>> >>> that does seem like the right place to put it). I'm surprised >>>>>>>> that the >>>>>>>> >>> circularity was so problematic, though. Why isn't it >>>>>>>> sufficient to have an >>>>>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>>>>> >>> >>>>>>>> >>> -Michael >>>>>>>> >>> >>>>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>>>> >>> wrote: >>>>>>>> >>>> >>>>>>>> >>>> Hey Michael, >>>>>>>> >>>> I actually proposed something along these lines that got OK'd >>>>>>>> by >>>>>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>>>>> actually doing >>>>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>>>> some nasty >>>>>>>> >>>> module cycles in base that happen when you try to weave things >>>>>>>> around so >>>>>>>> >>>> that the standard error "message here" call includes some >>>>>>>> stack trace info. >>>>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>>>> >>>> >>>>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work >>>>>>>> and just >>>>>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>>>>> love some >>>>>>>> >>>> headway on that front. >>>>>>>> >>>> >>>>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>>>> info data >>>>>>>> >>>> in >7.10 to provide useful stack traces in the default builds >>>>>>>> for GHC afaik, >>>>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>>>> currenlty only work >>>>>>>> >>>> on profiled builds >>>>>>>> >>>> >>>>>>>> >>>> cheers >>>>>>>> >>>> -Carter >>>>>>>> >>>> >>>>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>>>> mgsloan at gmail.com> >>>>>>>> >>>> wrote: >>>>>>>> >>>>> >>>>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>>>> could be >>>>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], >>>>>>>> but we have >>>>>>>> >>>>> no generic way to include this information with exceptions. >>>>>>>> >>>>> >>>>>>>> >>>>> Proposed Solution >>>>>>>> >>>>> ================= >>>>>>>> >>>>> >>>>>>>> >>>>> The proposed solution is to add a list of `SomeExceptionInfo` >>>>>>>> to the >>>>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>>>> information >>>>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>>>> mechanism >>>>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>>>> `Exception` type >>>>>>>> >>>>> works: >>>>>>>> >>>>> >>>>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>>>> >>>>> >>>>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>>>> >>>>> SomeExceptionInfo a >>>>>>>> >>>>> >>>>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>>>> >>>>> >>>>>>>> >>>>> addExceptionInfo >>>>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>>>> >>>>> => a -> e -> SomeException >>>>>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo >>>>>>>> e xs) = >>>>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>>>> >>>>> >>>>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that >>>>>>>> `Exception` has, >>>>>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>>>>> exception >>>>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>>>> necessary >>>>>>>> >>>>> casting. >>>>>>>> >>>>> >>>>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>>>> constraint >>>>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to have >>>>>>>> a new >>>>>>>> >>>>> class for this so that: >>>>>>>> >>>>> >>>>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>>>> >>>>> implementation, for when this extra info is presented to >>>>>>>> the user. >>>>>>>> >>>>> This function would be invoked by the `show` implementation >>>>>>>> for >>>>>>>> >>>>> `SomeException`. >>>>>>>> >>>>> >>>>>>>> >>>>> * Types need to opt-in to be usable with >>>>>>>> `SomeExceptionInfo`. >>>>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>>>> acting as >>>>>>>> >>>>> such an annotation. Having a class for this allows you to >>>>>>>> ask GHCI >>>>>>>> >>>>> about all in-scope exception info types via `:info >>>>>>>> ExceptionInfo`. >>>>>>>> >>>>> >>>>>>>> >>>>> Backwards Compatibility >>>>>>>> >>>>> ======================= >>>>>>>> >>>>> >>>>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. >>>>>>>> This means >>>>>>>> >>>>> that this change could be made without breaking code: >>>>>>>> >>>>> >>>>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ where >>>>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>>>> >>>>> >>>>>>>> >>>>> Note that consumers of this do not need to enable >>>>>>>> `-XPatternSynonyms`. >>>>>>>> >>>>> >>>>>>>> >>>>> Applications >>>>>>>> >>>>> ============ >>>>>>>> >>>>> >>>>>>>> >>>>> Callstacks >>>>>>>> >>>>> ---------- >>>>>>>> >>>>> >>>>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>>>> callstacks to >>>>>>>> >>>>> exceptions: >>>>>>>> >>>>> >>>>>>>> >>>>> newtype ExceptionCallStack = >>>>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: [String] >>>>>>>> } >>>>>>>> >>>>> deriving Typeable >>>>>>>> >>>>> >>>>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>>>> >>>>> >>>>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>>>> >>>>> throwIOWithStack e = do >>>>>>>> >>>>> stack <- currentCallStack >>>>>>>> >>>>> if null stack >>>>>>>> >>>>> then throwIO e >>>>>>>> >>>>> else throwIO (addExceptionInfo >>>>>>>> (ExceptionCallStack stack) >>>>>>>> >>>>> e) >>>>>>>> >>>>> >>>>>>>> >>>>> I see little downside for making something like this the >>>>>>>> default >>>>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>>>> `SomeException` >>>>>>>> >>>>> would add an additional stacktrace to its annotation, much >>>>>>>> like the >>>>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>>>> >>>>> stacktraces would be associated with the exception, rather >>>>>>>> than just >>>>>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>>>> programs, or in >>>>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>>>> functioning. >>>>>>>> >>>>> >>>>>>>> >>>>> Throwing Exceptions in Handlers >>>>>>>> >>>>> ------------------------------- >>>>>>>> >>>>> >>>>>>>> >>>>> Example: >>>>>>>> >>>>> >>>>>>>> >>>>> main = >>>>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>>>> >>>>> >>>>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't >>>>>>>> see it, >>>>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes a >>>>>>>> few >>>>>>>> >>>>> issues: >>>>>>>> >>>>> >>>>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>>>> yielded to >>>>>>>> >>>>> the user, then the more informative error is lost. >>>>>>>> >>>>> >>>>>>>> >>>>> 2. Callers who expect to catch the "Informative error >>>>>>>> message" won't >>>>>>>> >>>>> run their handlers for this exception type. >>>>>>>> >>>>> >>>>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to >>>>>>>> the >>>>>>>> >>>>> exception: >>>>>>>> >>>>> >>>>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>>>> >>>>> deriving Typeable >>>>>>>> >>>>> >>>>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>>>> >>>>> displayExceptionInfo fe = >>>>>>>> >>>>> "thrown while handling " ++ >>>>>>>> >>>>> displayException (unExceptionCause fe) >>>>>>>> >>>>> >>>>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>>>> >>>>> where >>>>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) >>>>>>>> -> >>>>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>>>> >>>>> where >>>>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>>>> >>>>> >>>>>>>> >>>>> This implementation of `catch` is written in a >>>>>>>> backwards-compatible >>>>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>>>> still the >>>>>>>> >>>>> one that gets rethrown. The "original" exception is recorded >>>>>>>> in the >>>>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>>>> >>>>> `__context__` attribute[3]. This was brought to my attention >>>>>>>> in a >>>>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>>>> suppress >>>>>>>> >>>>> the original exception[5]. >>>>>>>> >>>>> >>>>>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>>>> >>>>> compatibility. With the earlier example, a `catch` handler >>>>>>>> for >>>>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't >>>>>>>> the >>>>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>>>> variant of >>>>>>>> >>>>> catch which instead throws the original exception. This >>>>>>>> might be a >>>>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>>>> `finally`. >>>>>>>> >>>>> >>>>>>>> >>>>> Asynchronous Exceptions >>>>>>>> >>>>> ----------------------- >>>>>>>> >>>>> >>>>>>>> >>>>> Currently, the only reliable way to catch exceptions, >>>>>>>> ignoring async >>>>>>>> >>>>> exceptions, is to fork a new thread. This is the approach >>>>>>>> used by the >>>>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly that >>>>>>>> we need >>>>>>>> >>>>> to go to such lengths due to the lack of one bit of >>>>>>>> information about >>>>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>>>> >>>>> >>>>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this >>>>>>>> doesn't enforce >>>>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>>>> exception. >>>>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>>>> exception is >>>>>>>> >>>>> synchronous or asynchronous. Here's what this would look >>>>>>>> like: >>>>>>>> >>>>> >>>>>>>> >>>>> data IsAsync = IsAsync >>>>>>>> >>>>> deriving (Typeable, Show) >>>>>>>> >>>>> >>>>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>>>> >>>>> displayExceptionInfo IsAsync = "thrown asynchronously" >>>>>>>> >>>>> >>>>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>>>> >>>>> >>>>>>>> >>>>> The details of this get a bit tricky: What happens if >>>>>>>> `throwIO` is >>>>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` >>>>>>>> flag set? >>>>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>>>> interactions >>>>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>>>> >>>>> exceptions. Such details are explained in a post by Edsko de >>>>>>>> Vries[8] >>>>>>>> >>>>> and ghc trac #2558[9]. >>>>>>>> >>>>> >>>>>>>> >>>>> Issue: fromException loses info >>>>>>>> >>>>> =============================== >>>>>>>> >>>>> >>>>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>>>> >>>>> >>>>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>>>> usually form >>>>>>>> >>>>> a prism. In other words, when `fromException` yields a >>>>>>>> `Just`, you >>>>>>>> >>>>> should get the same `SomeException` when using `toException` >>>>>>>> on that >>>>>>>> >>>>> value. >>>>>>>> >>>>> >>>>>>>> >>>>> For example, >>>>>>>> >>>>> >>>>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>>>> throwIO ex >>>>>>>> >>>>> >>>>>>>> >>>>> is equivalent to >>>>>>>> >>>>> >>>>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO >>>>>>>> ex >>>>>>>> >>>>> >>>>>>>> >>>>> However, with exception info added to just `SomeException`, >>>>>>>> and no >>>>>>>> >>>>> changes to existing `Exception` instances, this >>>>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception type >>>>>>>> get >>>>>>>> >>>>> rethrown with less information. >>>>>>>> >>>>> >>>>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as >>>>>>>> a field >>>>>>>> >>>>> to existing `Exception` instances. This would require the >>>>>>>> use of >>>>>>>> >>>>> non-default implementations of the `toException` and >>>>>>>> `fromException` >>>>>>>> >>>>> instances. >>>>>>>> >>>>> >>>>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>>>> which also >>>>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>>>> >>>>> >>>>>>>> >>>>> [1] >>>>>>>> >>>>> >>>>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>>>> >>>>> [2] >>>>>>>> >>>>> >>>>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>>>> >>>>> [4] >>>>>>>> >>>>> >>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>>>> >>>>> [5] >>>>>>>> >>>>> >>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>>>> >>>>> >>>>>>>> >>>>> _______________________________________________ >>>>>>>> >>>>> Libraries mailing list >>>>>>>> >>>>> Libraries at haskell.org >>>>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>> >>>>> >>>>>>>> >>>> >>>>>>>> >>> >>>>>>>> >> >>>>>>>> > >>>>>>>> > >>>>>>>> > _______________________________________________ >>>>>>>> > Libraries mailing list >>>>>>>> > Libraries at haskell.org >>>>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>> > >>>>>>>> >>>>>>> >>>>>>> >>>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Sun Apr 26 23:18:18 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Sun, 26 Apr 2015 16:18:18 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Sun, Apr 26, 2015 at 2:37 PM, Edward Kmett wrote: > I have to confess that I don't really like this proposal in its current > form. > > We use a little bit of Typeable magic in SomeException to model an open > sum type. It is more or less "just enough" to get us an open set of > exceptions on which we can match. > > That gives us a nice case analysis construction, we can basically reason > type by type and ask if SomeException _is_ a particular data type without > losing any information. > > Theoretically it means I can give you a nice prism or case handler for it, > match on it, rethrow it and nothing is lost. > > This proposal gives up a very nice property in exchange for an ad hoc > ability to decorate exceptions with anything we want. This strikes me as a > short term gain in exchange for giving up a lot of future reasoning power. > What is your exception decorated with? Go spend O(n) time rummaging through > the list of attached decorations to find out! =/ > Yep, I agree that giving up this property sucks. It's discussed at the end of the proposal. Rummaging through the list of decorations also sucks. My reasoning for that being acceptable is that if these annotations are used primarily for diagnostic purposes, then performance isn't so crucial. I'm not offering a concrete worked solution, but there are many other > points in this design space. e.g. having a class to let you attach the > particular information you want to particular exceptions, having an > exception type you can throw with a stack intact that acts as an exception > transformer, etc. > > None of those require us to give up the simplicity of the open exceptions, > but those first two obvious directions have obvious drawbacks, hence why > "I'm not offering a concrete worked solution." > > Davean's variant narrows the focus down considerably. Limiting it to just > the issue at hand, rather than trying to construct a solution to all sorts > of problems we haven't even thought of yet. I could get behind something > with a more retrenched scope, like that. > To me, whether we use closed or open datatypes is tertiary to the main issue of how info gets associated with exceptions. If the main issue with my proposal is the breakage of the information preservation of `fromException`, as far as I can tell, that is not addressed by Davean's proposal. So, the narrowing of scope bought us nothing but having simpler types to talk about. One thing to note is that `fromException` does not guarantee preservation of information. So, this only breaks an informal property, not one that is documented. Admittedly, it's one that people are used to relying on. > That said, I'd very much rather err on the side of doing nothing rather > than do the wrong thing here. > > We'll be stuck with it for a long time. > Yes, such core changes should be made with great care. I hesitated to post the proposal due to this, but was hoping that a more palatable, backwards compatible solution would come up in discussion. While I don't want to get stuck with a bad API, I also don't want to be stuck with uninformative exceptions. The new parts of the API can be stuck in an "Internal" module, and marked specifically for debugging purposes only. This way, base reserves the right to revert this particular API choice if a better option comes along. Personally, I want callstacks for every exception thrown, and that's what this proposal provides. > -Edward > > On Sun, Apr 26, 2015 at 4:26 PM, Michael Sloan wrote: > >> Right, we have a choice between making a breaking change towards a more >> standard API, or using a rather new language extension (bidirectional >> pattern synonyms) to avoid breakage. >> >> On Thu, Apr 23, 2015 at 6:30 AM, Greg Weber wrote: >> >>> >>> >>> On Tue, Apr 21, 2015 at 1:55 PM, Michael Sloan >>> wrote: >>> >>>> >>>> On Tue, Apr 21, 2015 at 8:23 AM, Greg Weber >>>> wrote: >>>> >>>>> >>>>> On Tue, Apr 14, 2015 at 11:38 AM, Michael Sloan >>>>> wrote: >>>>> >>>>>> data SomeException = forall e . Exception e => >>>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>> >>>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>> SomeExceptionInfo a >>>>> >>>>> >>>>> Is it necessary for SomeExceptionWithInfo to have a list of a forall >>>>> data type? >>>>> Are Exceptions really that mysterious, or can we more concretely >>>>> describe the information that should be attached to an exception? >>>>> >>>>> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >>>>> >>>> >>>> I did consider this option, but I think as soon as a fixed set is >>>> selected, someone's going to put something else in it. Usually we wouldn't >>>> want to use such a 'dynamic' mechanism in Haskell, but it's appropriate for >>>> something so global as the type used to throw exceptions. >>>> >>> >>> The usual approach is to use information hiding. We are being rescued by >>> pattern synonyms right now because the constructor is directly exported. >>> Why not hide what needs to be hidden to make this more extensible and >>> use smart constructors, etc?. >>> >>> >>>> >>>> >>>>> I am still open to the idea of adding a forall data scratchpad, but >>>>> can we at least try to specify some standard fields? >>>>> >>>>> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >>>>> [SomeExceptionInfo] >>>>> >>>> >>>> This is an interesting idea. I particularly see value in having >>>> 'IsAsync' be a part of the Exception. This is because `throwIO` / `throw` >>>> would need to set this to False when rethrowing async exceptions. >>>> >>> >>> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From johnw at newartisans.com Sun Apr 26 23:45:29 2015 From: johnw at newartisans.com (John Wiegley) Date: Sun, 26 Apr 2015 18:45:29 -0500 Subject: Proposal: Add exception info In-Reply-To: (Edward Kmett's message of "Sun, 26 Apr 2015 17:37:52 -0400") References: Message-ID: >>>>> Edward Kmett writes: > That said, I'd very much rather err on the side of doing nothing rather than > do the wrong thing here. > We'll be stuck with it for a long time. I agree with Edward's sentiments. John From mgsloan at gmail.com Sun Apr 26 23:52:56 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Sun, 26 Apr 2015 16:52:56 -0700 Subject: Exceptions with Context Re: Proposal: Add exception info In-Reply-To: References: Message-ID: So, based on discussion in IRC, it's clear that with Davean's proposal the thrower would need to call a function which does something like: stack <- currentCallStack throwIO (WithStack stack e) However, this requires that every thrower change their code if they want to provide callstacks. Moreover, every exception handler that wants to handle this exception would need to change as well. This would be a breaking API change for every library that adds support for callstacks. Perhaps this is our only viable option.. With my proposal, we can have every use of throw provide a callstack, but lose the information preservation of fromException. -Michael On Tue, Apr 21, 2015 at 9:08 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > no michael, Daveans proposal is that we add certain catchWithExtraInfo :: > Exception e => IO a -> (ExtraInfo -> e -> IO a ) -> IO a style operations > to the exceptions modules, for various choices of "extraInfo" > > The idea being, NO current exception codes should have to change. Nor does > SomeException need to change. > i will try to articulate my concerns about your proposed design in more > details on the other proposal thread after i've had a bit more sleep and > thought about it more > > > On Tue, Apr 21, 2015 at 11:50 PM, Michael Sloan wrote: > >> Either I am misunderstanding davean's proposal, or you are >> misunderstanding mine. Namely: >> >> * How is his proposal more extensible? His specializes it to just >> passing callstack information. >> >> * I'm not sure exactly how he proposes to change the catch. If it's >> changed to always preserve the extra exception info, then this will be a >> massive API breakage. >> >> -Michael >> >> On Tue, Apr 21, 2015 at 7:23 PM, Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> hrm, i like this proposal more, and it seems like with some fleshing >>> out it can be strictly more extensible yet backwards compatible than >>> michael's >>> >>> I'll need to mull it a bit more before I cast my vote, but this seems to >>> sketch out a design that provides the same information, but in a more >>> extensible/backwards compatible fashion (at least in a first cut of >>> thinking about it) >>> >>> (i'm splitting this into a new thread so the discussions dont get mixed >>> up) >>> >>> On Tue, Apr 21, 2015 at 9:40 PM, davean wrote: >>> >>>> So, I've had a number of issues with exceptions. This has been one of >>>> them. I don't really like this proposal as it stands though as it seems to >>>> make catch a specific exception with said extra info more difficult. >>>> >>>> This is data Control.Exception can move around on its own though, >>>> right? The problem really isn't passing it internal, we could just make a >>>> (Stack, SomeException) tuple just fine, in theory I think (I'll admit I've >>>> not actually reviewed the code, and this isn't meant as a complete proposal >>>> but more a thought experiment). The problem is code handling the data and >>>> working with old code while not losing any of the power of the current >>>> system. >>>> >>>> So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>> >>>> Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> >>>> IO a >>>> If we want access to the new information, but that's not really >>>> satisfactory. >>>> >>>> Real code regularly wants to (picking an arbitrary instance of >>>> Exception) do: catch :: IO a -> (IOError -> IO a) -> IO a >>>> only we still want new data. >>>> >>>> Now one could do something like: catch :: IO a -> (Stack -> IOError -> >>>> IO a) -> IO a >>>> but that is not very upgradable and it breaks existing code. >>>> >>>> But this is just a matter of requesting information, so one could do >>>> something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a >>>> where: data WithStack e = WithStack Stack e >>>> Or maybe one just addes: catchWithContext :: Exception e => IO a -> >>>> (Context -> e -> IO a) -> IO a >>>> Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> IO >>>> a >>>> >>>> Now existing code continues to run and we can feed our exception >>>> handlers the data they want, even when we want some specific exception >>>> instead of just any exception. >>>> >>>> Now that still leave a hole in what I want out of exceptions. We're >>>> still short of programmatic interrogating them, or even telling what the >>>> exception was if we didn't expect it! >>>> >>>> Consider AssertionFailed >>>> . >>>> Its show instance is "showsPrec _ (AssertionFailed err) = showString err", >>>> so if we print out the SomeException, we get whatever string is in >>>> AssertionFailed. Which is great if that string makes sense. But you see >>>> that on your console and its a bit baffling if it doesn't. It could even be >>>> a lie, I can make that say something that looks like its a different >>>> exception. We can use the Typeable instance so the program can tell them >>>> apart at least though. Which works as long as the exception is >>>> single-constructor, or has a well-behaved show instance. What if we come >>>> across a monstrosity like >>>> http://hackage.haskell.org/package/http-conduit-2.1.5/docs/Network-HTTP-Conduit.html#g:12 >>>> and it doesn't have a nice show instance that says which on it is? If >>>> Exception added a Data constraint we could actually pull apart these >>>> exceptions and start to make proper sense of them reliably. >>>> >>>> Once you have that there are quite a few useful things you can do with >>>> the exceptions you didn't expect. Currently you could only do them by >>>> enumerating every possible exception which of course doesn't work for the >>>> unexpected. >>>> >>>> On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan >>>> wrote: >>>> >>>>> No, this proposal is not specifically about stack traces, that is just >>>>> one of the usecases. Instead, this is about a general mechanism for >>>>> including extra information with exceptions. The core of this proposal is >>>>> still relevant even if the behavior of error / throw / throwTo / etc remain >>>>> unchanged. >>>>> >>>>> I'm not familiar with how the new dwarf stuff will interact with >>>>> throwing / displaying exceptions. It seems like this would require having >>>>> the debugger break at the throw site, and exceptions would still lack stack >>>>> traces. Having informative stack traces is quite orthogonal to having a >>>>> good place to store them. >>>>> >>>>> Note that in my original proposal text I mentioned that this is >>>>> agnostic of the particular source of the stack trace. In particular, this >>>>> could be used with a profiling stack trace, implicit callstack, or, indeed, >>>>> these traces via dwarf. >>>>> >>>>> -Michael >>>>> >>>>> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >>>>> carter.schonwald at gmail.com> wrote: >>>>> >>>>>> On a more important note: assuming ghc 7.12 has support for >>>>>> informative stack traces via dwarf by default, wouldn't that eliminate the >>>>>> need for this proposal? Namely : there perhaps should be some reasonable >>>>>> way to talk about concatting stack traces perhaps? >>>>>> >>>>>> Phrased differently: how is the info that should perhaps be in >>>>>> informative stack traces not subsuming the info of this proposal? >>>>>> >>>>>> >>>>>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>>>>> >>>>>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>>>>> locations to such functions: https://phabricator.haskell.org/D861 >>>>>>> >>>>>>> However, there are some issues with changing the API of these >>>>>>> functions: https://phabricator.haskell.org/D861#23250 >>>>>>> >>>>>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" >>>>>>> thread) >>>>>>> >>>>>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>>>>> wrote: >>>>>>> >>>>>>>> Hmm, that patch doesn't appear to add stack traces to >>>>>>>> 'Prelude.error', which is what Carter wants here. Also, I think it would >>>>>>>> be done with profiling callstacks rather than implicit callstacks. But >>>>>>>> it's certainly also useful to have functions which do the same with >>>>>>>> implicit callstacks! >>>>>>>> >>>>>>>> >>>>>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>>>>> >>>>>>>>> https://phabricator.haskell.org/D578 >>>>>>>>> >>>>>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>>>>> wrote: >>>>>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>>>>> > wrote: >>>>>>>>> >> >>>>>>>>> >> if you can patch prelude error to include stack traces, i will >>>>>>>>> owe you a >>>>>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>>>>> christmas. :) >>>>>>>>> > >>>>>>>>> > >>>>>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>>>>> Looking >>>>>>>>> > forward to ICFP beers either way :D >>>>>>>>> > >>>>>>>>> >> i can't speak for how a different patch might work out, because >>>>>>>>> thats not >>>>>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>>>>> results! >>>>>>>>> >> -Carter >>>>>>>>> >> >>>>>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan < >>>>>>>>> mgsloan at gmail.com> wrote: >>>>>>>>> >>> >>>>>>>>> >>> Hi Carter! >>>>>>>>> >>> >>>>>>>>> >>> Interesting! This thread, right? >>>>>>>>> >>> >>>>>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>>>>> >>> >>>>>>>>> >>> I haven't tried this as a patch to base, but I'm certain that >>>>>>>>> the core of >>>>>>>>> >>> the proposal has no extra dependencies. Note that the >>>>>>>>> proposal isn't about >>>>>>>>> >>> stack traces in particular - that's just one application of >>>>>>>>> being able to >>>>>>>>> >>> throw exceptions with extra information. >>>>>>>>> >>> >>>>>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with >>>>>>>>> stack traces, >>>>>>>>> >>> this functionality could be provided outside of >>>>>>>>> `Control.Exception` (though, >>>>>>>>> >>> that does seem like the right place to put it). I'm surprised >>>>>>>>> that the >>>>>>>>> >>> circularity was so problematic, though. Why isn't it >>>>>>>>> sufficient to have an >>>>>>>>> >>> hs-boot file for `GHC.Stack`, which exports `currentCallStack`? >>>>>>>>> >>> >>>>>>>>> >>> -Michael >>>>>>>>> >>> >>>>>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>>>>> >>> wrote: >>>>>>>>> >>>> >>>>>>>>> >>>> Hey Michael, >>>>>>>>> >>>> I actually proposed something along these lines that got OK'd >>>>>>>>> by >>>>>>>>> >>>> libraries early this past fall, the main challenge we hit was >>>>>>>>> actually doing >>>>>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>>>>> some nasty >>>>>>>>> >>>> module cycles in base that happen when you try to weave >>>>>>>>> things around so >>>>>>>>> >>>> that the standard error "message here" call includes some >>>>>>>>> stack trace info. >>>>>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>>>>> >>>> >>>>>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work >>>>>>>>> and just >>>>>>>>> >>>> gave up because of the cycles. We (and others) would probably >>>>>>>>> love some >>>>>>>>> >>>> headway on that front. >>>>>>>>> >>>> >>>>>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>>>>> info data >>>>>>>>> >>>> in >7.10 to provide useful stack traces in the default builds >>>>>>>>> for GHC afaik, >>>>>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>>>>> currenlty only work >>>>>>>>> >>>> on profiled builds >>>>>>>>> >>>> >>>>>>>>> >>>> cheers >>>>>>>>> >>>> -Carter >>>>>>>>> >>>> >>>>>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>>>>> mgsloan at gmail.com> >>>>>>>>> >>>> wrote: >>>>>>>>> >>>>> >>>>>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>>>>> could be >>>>>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], >>>>>>>>> but we have >>>>>>>>> >>>>> no generic way to include this information with exceptions. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Proposed Solution >>>>>>>>> >>>>> ================= >>>>>>>>> >>>>> >>>>>>>>> >>>>> The proposed solution is to add a list of >>>>>>>>> `SomeExceptionInfo` to the >>>>>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>>>>> information >>>>>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>>>>> mechanism >>>>>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>>>>> `Exception` type >>>>>>>>> >>>>> works: >>>>>>>>> >>>>> >>>>>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>>>>> >>>>> >>>>>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>>>>> >>>>> SomeExceptionInfo a >>>>>>>>> >>>>> >>>>>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>>>>> >>>>> >>>>>>>>> >>>>> addExceptionInfo >>>>>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>>>>> >>>>> => a -> e -> SomeException >>>>>>>>> >>>>> addExceptionInfo x (toException -> SomeExceptionWithInfo >>>>>>>>> e xs) = >>>>>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>>>>> >>>>> >>>>>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that >>>>>>>>> `Exception` has, >>>>>>>>> >>>>> because I don't see much point in supporting a hierarchy for >>>>>>>>> exception >>>>>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>>>>> necessary >>>>>>>>> >>>>> casting. >>>>>>>>> >>>>> >>>>>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>>>>> constraint >>>>>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to >>>>>>>>> have a new >>>>>>>>> >>>>> class for this so that: >>>>>>>>> >>>>> >>>>>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>>>>> >>>>> implementation, for when this extra info is presented to >>>>>>>>> the user. >>>>>>>>> >>>>> This function would be invoked by the `show` >>>>>>>>> implementation for >>>>>>>>> >>>>> `SomeException`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> * Types need to opt-in to be usable with >>>>>>>>> `SomeExceptionInfo`. >>>>>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>>>>> acting as >>>>>>>>> >>>>> such an annotation. Having a class for this allows you to >>>>>>>>> ask GHCI >>>>>>>>> >>>>> about all in-scope exception info types via `:info >>>>>>>>> ExceptionInfo`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Backwards Compatibility >>>>>>>>> >>>>> ======================= >>>>>>>>> >>>>> >>>>>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. >>>>>>>>> This means >>>>>>>>> >>>>> that this change could be made without breaking code: >>>>>>>>> >>>>> >>>>>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ >>>>>>>>> where >>>>>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>>>>> >>>>> >>>>>>>>> >>>>> Note that consumers of this do not need to enable >>>>>>>>> `-XPatternSynonyms`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Applications >>>>>>>>> >>>>> ============ >>>>>>>>> >>>>> >>>>>>>>> >>>>> Callstacks >>>>>>>>> >>>>> ---------- >>>>>>>>> >>>>> >>>>>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>>>>> callstacks to >>>>>>>>> >>>>> exceptions: >>>>>>>>> >>>>> >>>>>>>>> >>>>> newtype ExceptionCallStack = >>>>>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: >>>>>>>>> [String] } >>>>>>>>> >>>>> deriving Typeable >>>>>>>>> >>>>> >>>>>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>>>>> >>>>> displayExceptionInfo = unlines . unExceptionCallStack >>>>>>>>> >>>>> >>>>>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>>>>> >>>>> throwIOWithStack e = do >>>>>>>>> >>>>> stack <- currentCallStack >>>>>>>>> >>>>> if null stack >>>>>>>>> >>>>> then throwIO e >>>>>>>>> >>>>> else throwIO (addExceptionInfo >>>>>>>>> (ExceptionCallStack stack) >>>>>>>>> >>>>> e) >>>>>>>>> >>>>> >>>>>>>>> >>>>> I see little downside for making something like this the >>>>>>>>> default >>>>>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>>>>> `SomeException` >>>>>>>>> >>>>> would add an additional stacktrace to its annotation, much >>>>>>>>> like the >>>>>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>>>>> >>>>> stacktraces would be associated with the exception, rather >>>>>>>>> than just >>>>>>>>> >>>>> listing locations that exceptions were thrown. This makes it >>>>>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>>>>> programs, or in >>>>>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>>>>> functioning. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Throwing Exceptions in Handlers >>>>>>>>> >>>>> ------------------------------- >>>>>>>>> >>>>> >>>>>>>>> >>>>> Example: >>>>>>>>> >>>>> >>>>>>>>> >>>>> main = >>>>>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>>>>> >>>>> >>>>>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user doesn't >>>>>>>>> see it, >>>>>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes >>>>>>>>> a few >>>>>>>>> >>>>> issues: >>>>>>>>> >>>>> >>>>>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>>>>> yielded to >>>>>>>>> >>>>> the user, then the more informative error is lost. >>>>>>>>> >>>>> >>>>>>>>> >>>>> 2. Callers who expect to catch the "Informative error >>>>>>>>> message" won't >>>>>>>>> >>>>> run their handlers for this exception type. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to >>>>>>>>> the >>>>>>>>> >>>>> exception: >>>>>>>>> >>>>> >>>>>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>>>>> >>>>> deriving Typeable >>>>>>>>> >>>>> >>>>>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>>>>> >>>>> displayExceptionInfo fe = >>>>>>>>> >>>>> "thrown while handling " ++ >>>>>>>>> >>>>> displayException (unExceptionCause fe) >>>>>>>>> >>>>> >>>>>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>>>>> >>>>> where >>>>>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: SomeException) >>>>>>>>> -> >>>>>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>>>>> >>>>> where >>>>>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>>>>> >>>>> >>>>>>>>> >>>>> This implementation of `catch` is written in a >>>>>>>>> backwards-compatible >>>>>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>>>>> still the >>>>>>>>> >>>>> one that gets rethrown. The "original" exception is >>>>>>>>> recorded in the >>>>>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>>>>> >>>>> `__context__` attribute[3]. This was brought to my >>>>>>>>> attention in a >>>>>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>>>>> suppress >>>>>>>>> >>>>> the original exception[5]. >>>>>>>>> >>>>> >>>>>>>>> >>>>> This doesn't directly resolve issue #2, due to this backwards >>>>>>>>> >>>>> compatibility. With the earlier example, a `catch` handler >>>>>>>>> for >>>>>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it isn't >>>>>>>>> the >>>>>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>>>>> variant of >>>>>>>>> >>>>> catch which instead throws the original exception. This >>>>>>>>> might be a >>>>>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>>>>> `finally`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Asynchronous Exceptions >>>>>>>>> >>>>> ----------------------- >>>>>>>>> >>>>> >>>>>>>>> >>>>> Currently, the only reliable way to catch exceptions, >>>>>>>>> ignoring async >>>>>>>>> >>>>> exceptions, is to fork a new thread. This is the approach >>>>>>>>> used by the >>>>>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly >>>>>>>>> that we need >>>>>>>>> >>>>> to go to such lengths due to the lack of one bit of >>>>>>>>> information about >>>>>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>>>>> >>>>> >>>>>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this >>>>>>>>> doesn't enforce >>>>>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>>>>> exception. >>>>>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>>>>> exception is >>>>>>>>> >>>>> synchronous or asynchronous. Here's what this would look >>>>>>>>> like: >>>>>>>>> >>>>> >>>>>>>>> >>>>> data IsAsync = IsAsync >>>>>>>>> >>>>> deriving (Typeable, Show) >>>>>>>>> >>>>> >>>>>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>>>>> >>>>> displayExceptionInfo IsAsync = "thrown >>>>>>>>> asynchronously" >>>>>>>>> >>>>> >>>>>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>>>>> >>>>> >>>>>>>>> >>>>> The details of this get a bit tricky: What happens if >>>>>>>>> `throwIO` is >>>>>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` >>>>>>>>> flag set? >>>>>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>>>>> interactions >>>>>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" async >>>>>>>>> >>>>> exceptions. Such details are explained in a post by Edsko >>>>>>>>> de Vries[8] >>>>>>>>> >>>>> and ghc trac #2558[9]. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Issue: fromException loses info >>>>>>>>> >>>>> =============================== >>>>>>>>> >>>>> >>>>>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>>>>> >>>>> >>>>>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>>>>> usually form >>>>>>>>> >>>>> a prism. In other words, when `fromException` yields a >>>>>>>>> `Just`, you >>>>>>>>> >>>>> should get the same `SomeException` when using `toException` >>>>>>>>> on that >>>>>>>>> >>>>> value. >>>>>>>>> >>>>> >>>>>>>>> >>>>> For example, >>>>>>>>> >>>>> >>>>>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>>>>> throwIO ex >>>>>>>>> >>>>> >>>>>>>>> >>>>> is equivalent to >>>>>>>>> >>>>> >>>>>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> throwIO >>>>>>>>> ex >>>>>>>>> >>>>> >>>>>>>>> >>>>> However, with exception info added to just `SomeException`, >>>>>>>>> and no >>>>>>>>> >>>>> changes to existing `Exception` instances, this >>>>>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception >>>>>>>>> type get >>>>>>>>> >>>>> rethrown with less information. >>>>>>>>> >>>>> >>>>>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` as >>>>>>>>> a field >>>>>>>>> >>>>> to existing `Exception` instances. This would require the >>>>>>>>> use of >>>>>>>>> >>>>> non-default implementations of the `toException` and >>>>>>>>> `fromException` >>>>>>>>> >>>>> instances. >>>>>>>>> >>>>> >>>>>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>>>>> which also >>>>>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>>>>> >>>>> >>>>>>>>> >>>>> [1] >>>>>>>>> >>>>> >>>>>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>>>>> >>>>> [2] >>>>>>>>> >>>>> >>>>>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>>>>> >>>>> [4] >>>>>>>>> >>>>> >>>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>>>>> >>>>> [5] >>>>>>>>> >>>>> >>>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>>>>> >>>>> >>>>>>>>> >>>>> _______________________________________________ >>>>>>>>> >>>>> Libraries mailing list >>>>>>>>> >>>>> Libraries at haskell.org >>>>>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>>> >>>>> >>>>>>>>> >>>> >>>>>>>>> >>> >>>>>>>>> >> >>>>>>>>> > >>>>>>>>> > >>>>>>>>> > _______________________________________________ >>>>>>>>> > Libraries mailing list >>>>>>>>> > Libraries at haskell.org >>>>>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>>> > >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>> >>>>> >>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Sun Apr 26 23:57:05 2015 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Sun, 26 Apr 2015 19:57:05 -0400 Subject: Exceptions with Context Re: Proposal: Add exception info In-Reply-To: References: Message-ID: no, the idea / premise is there'd be a new "throwWithCallStack" and or "throwWithExtraInfo" the POINT here is there no point in doing changes to exception machinery UNTIL those various new stack trace pieces ?RE PRESENT. :) On Sun, Apr 26, 2015 at 7:52 PM, Michael Sloan wrote: > So, based on discussion in IRC, it's clear that with Davean's proposal the > thrower would need to call a function which does something like: > > stack <- currentCallStack > throwIO (WithStack stack e) > > However, this requires that every thrower change their code if they want > to provide callstacks. Moreover, every exception handler that wants to > handle this exception would need to change as well. This would be a > breaking API change for every library that adds support for callstacks. > Perhaps this is our only viable option.. > > With my proposal, we can have every use of throw provide a callstack, but > lose the information preservation of fromException. > > -Michael > > On Tue, Apr 21, 2015 at 9:08 PM, Carter Schonwald < > carter.schonwald at gmail.com> wrote: > >> no michael, Daveans proposal is that we add certain catchWithExtraInfo :: >> Exception e => IO a -> (ExtraInfo -> e -> IO a ) -> IO a style operations >> to the exceptions modules, for various choices of "extraInfo" >> >> The idea being, NO current exception codes should have to change. Nor >> does SomeException need to change. >> i will try to articulate my concerns about your proposed design in more >> details on the other proposal thread after i've had a bit more sleep and >> thought about it more >> >> >> On Tue, Apr 21, 2015 at 11:50 PM, Michael Sloan >> wrote: >> >>> Either I am misunderstanding davean's proposal, or you are >>> misunderstanding mine. Namely: >>> >>> * How is his proposal more extensible? His specializes it to just >>> passing callstack information. >>> >>> * I'm not sure exactly how he proposes to change the catch. If it's >>> changed to always preserve the extra exception info, then this will be a >>> massive API breakage. >>> >>> -Michael >>> >>> On Tue, Apr 21, 2015 at 7:23 PM, Carter Schonwald < >>> carter.schonwald at gmail.com> wrote: >>> >>>> hrm, i like this proposal more, and it seems like with some fleshing >>>> out it can be strictly more extensible yet backwards compatible than >>>> michael's >>>> >>>> I'll need to mull it a bit more before I cast my vote, but this seems >>>> to sketch out a design that provides the same information, but in a more >>>> extensible/backwards compatible fashion (at least in a first cut of >>>> thinking about it) >>>> >>>> (i'm splitting this into a new thread so the discussions dont get mixed >>>> up) >>>> >>>> On Tue, Apr 21, 2015 at 9:40 PM, davean wrote: >>>> >>>>> So, I've had a number of issues with exceptions. This has been one of >>>>> them. I don't really like this proposal as it stands though as it seems to >>>>> make catch a specific exception with said extra info more difficult. >>>>> >>>>> This is data Control.Exception can move around on its own though, >>>>> right? The problem really isn't passing it internal, we could just make a >>>>> (Stack, SomeException) tuple just fine, in theory I think (I'll admit I've >>>>> not actually reviewed the code, and this isn't meant as a complete proposal >>>>> but more a thought experiment). The problem is code handling the data and >>>>> working with old code while not losing any of the power of the current >>>>> system. >>>>> >>>>> So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>> >>>>> Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> >>>>> IO a >>>>> If we want access to the new information, but that's not really >>>>> satisfactory. >>>>> >>>>> Real code regularly wants to (picking an arbitrary instance of >>>>> Exception) do: catch :: IO a -> (IOError -> IO a) -> IO a >>>>> only we still want new data. >>>>> >>>>> Now one could do something like: catch :: IO a -> (Stack -> IOError -> >>>>> IO a) -> IO a >>>>> but that is not very upgradable and it breaks existing code. >>>>> >>>>> But this is just a matter of requesting information, so one could do >>>>> something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a >>>>> where: data WithStack e = WithStack Stack e >>>>> Or maybe one just addes: catchWithContext :: Exception e => IO a -> >>>>> (Context -> e -> IO a) -> IO a >>>>> Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> >>>>> IO a >>>>> >>>>> Now existing code continues to run and we can feed our exception >>>>> handlers the data they want, even when we want some specific exception >>>>> instead of just any exception. >>>>> >>>>> Now that still leave a hole in what I want out of exceptions. We're >>>>> still short of programmatic interrogating them, or even telling what the >>>>> exception was if we didn't expect it! >>>>> >>>>> Consider AssertionFailed >>>>> . >>>>> Its show instance is "showsPrec _ (AssertionFailed err) = showString err", >>>>> so if we print out the SomeException, we get whatever string is in >>>>> AssertionFailed. Which is great if that string makes sense. But you see >>>>> that on your console and its a bit baffling if it doesn't. It could even be >>>>> a lie, I can make that say something that looks like its a different >>>>> exception. We can use the Typeable instance so the program can tell them >>>>> apart at least though. Which works as long as the exception is >>>>> single-constructor, or has a well-behaved show instance. What if we come >>>>> across a monstrosity like >>>>> http://hackage.haskell.org/package/http-conduit-2.1.5/docs/Network-HTTP-Conduit.html#g:12 >>>>> and it doesn't have a nice show instance that says which on it is? If >>>>> Exception added a Data constraint we could actually pull apart these >>>>> exceptions and start to make proper sense of them reliably. >>>>> >>>>> Once you have that there are quite a few useful things you can do with >>>>> the exceptions you didn't expect. Currently you could only do them by >>>>> enumerating every possible exception which of course doesn't work for the >>>>> unexpected. >>>>> >>>>> On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan >>>>> wrote: >>>>> >>>>>> No, this proposal is not specifically about stack traces, that is >>>>>> just one of the usecases. Instead, this is about a general mechanism for >>>>>> including extra information with exceptions. The core of this proposal is >>>>>> still relevant even if the behavior of error / throw / throwTo / etc remain >>>>>> unchanged. >>>>>> >>>>>> I'm not familiar with how the new dwarf stuff will interact with >>>>>> throwing / displaying exceptions. It seems like this would require having >>>>>> the debugger break at the throw site, and exceptions would still lack stack >>>>>> traces. Having informative stack traces is quite orthogonal to having a >>>>>> good place to store them. >>>>>> >>>>>> Note that in my original proposal text I mentioned that this is >>>>>> agnostic of the particular source of the stack trace. In particular, this >>>>>> could be used with a profiling stack trace, implicit callstack, or, indeed, >>>>>> these traces via dwarf. >>>>>> >>>>>> -Michael >>>>>> >>>>>> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >>>>>> carter.schonwald at gmail.com> wrote: >>>>>> >>>>>>> On a more important note: assuming ghc 7.12 has support for >>>>>>> informative stack traces via dwarf by default, wouldn't that eliminate the >>>>>>> need for this proposal? Namely : there perhaps should be some reasonable >>>>>>> way to talk about concatting stack traces perhaps? >>>>>>> >>>>>>> Phrased differently: how is the info that should perhaps be in >>>>>>> informative stack traces not subsuming the info of this proposal? >>>>>>> >>>>>>> >>>>>>> On Tuesday, April 21, 2015, Michael Sloan wrote: >>>>>>> >>>>>>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>>>>>> locations to such functions: https://phabricator.haskell.org/D861 >>>>>>>> >>>>>>>> However, there are some issues with changing the API of these >>>>>>>> functions: https://phabricator.haskell.org/D861#23250 >>>>>>>> >>>>>>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" >>>>>>>> thread) >>>>>>>> >>>>>>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Hmm, that patch doesn't appear to add stack traces to >>>>>>>>> 'Prelude.error', which is what Carter wants here. Also, I think it would >>>>>>>>> be done with profiling callstacks rather than implicit callstacks. But >>>>>>>>> it's certainly also useful to have functions which do the same with >>>>>>>>> implicit callstacks! >>>>>>>>> >>>>>>>>> >>>>>>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>>>>>> >>>>>>>>>> https://phabricator.haskell.org/D578 >>>>>>>>>> >>>>>>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan >>>>>>>>>> wrote: >>>>>>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>>>>>> > wrote: >>>>>>>>>> >> >>>>>>>>>> >> if you can patch prelude error to include stack traces, i will >>>>>>>>>> owe you a >>>>>>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>>>>>> christmas. :) >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> > Sounds good! No promises, but I'll be giving this a try soon. >>>>>>>>>> Looking >>>>>>>>>> > forward to ICFP beers either way :D >>>>>>>>>> > >>>>>>>>>> >> i can't speak for how a different patch might work out, >>>>>>>>>> because thats not >>>>>>>>>> >> what I'd tried at the time. If you have a go, please share the >>>>>>>>>> results! >>>>>>>>>> >> -Carter >>>>>>>>>> >> >>>>>>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan < >>>>>>>>>> mgsloan at gmail.com> wrote: >>>>>>>>>> >>> >>>>>>>>>> >>> Hi Carter! >>>>>>>>>> >>> >>>>>>>>>> >>> Interesting! This thread, right? >>>>>>>>>> >>> >>>>>>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>>>>>> >>> >>>>>>>>>> >>> I haven't tried this as a patch to base, but I'm certain that >>>>>>>>>> the core of >>>>>>>>>> >>> the proposal has no extra dependencies. Note that the >>>>>>>>>> proposal isn't about >>>>>>>>>> >>> stack traces in particular - that's just one application of >>>>>>>>>> being able to >>>>>>>>>> >>> throw exceptions with extra information. >>>>>>>>>> >>> >>>>>>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with >>>>>>>>>> stack traces, >>>>>>>>>> >>> this functionality could be provided outside of >>>>>>>>>> `Control.Exception` (though, >>>>>>>>>> >>> that does seem like the right place to put it). I'm >>>>>>>>>> surprised that the >>>>>>>>>> >>> circularity was so problematic, though. Why isn't it >>>>>>>>>> sufficient to have an >>>>>>>>>> >>> hs-boot file for `GHC.Stack`, which exports >>>>>>>>>> `currentCallStack`? >>>>>>>>>> >>> >>>>>>>>>> >>> -Michael >>>>>>>>>> >>> >>>>>>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>>>>>> >>> wrote: >>>>>>>>>> >>>> >>>>>>>>>> >>>> Hey Michael, >>>>>>>>>> >>>> I actually proposed something along these lines that got >>>>>>>>>> OK'd by >>>>>>>>>> >>>> libraries early this past fall, the main challenge we hit >>>>>>>>>> was actually doing >>>>>>>>>> >>>> the enginering to add the stack traces to exceptions! theres >>>>>>>>>> some nasty >>>>>>>>>> >>>> module cycles in base that happen when you try to weave >>>>>>>>>> things around so >>>>>>>>>> >>>> that the standard error "message here" call includes some >>>>>>>>>> stack trace info. >>>>>>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>>>>>> >>>> >>>>>>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to work >>>>>>>>>> and just >>>>>>>>>> >>>> gave up because of the cycles. We (and others) would >>>>>>>>>> probably love some >>>>>>>>>> >>>> headway on that front. >>>>>>>>>> >>>> >>>>>>>>>> >>>> Theres also some in progress work to use the dwarf debugging >>>>>>>>>> info data >>>>>>>>>> >>>> in >7.10 to provide useful stack traces in the default >>>>>>>>>> builds for GHC afaik, >>>>>>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>>>>>> currenlty only work >>>>>>>>>> >>>> on profiled builds >>>>>>>>>> >>>> >>>>>>>>>> >>>> cheers >>>>>>>>>> >>>> -Carter >>>>>>>>>> >>>> >>>>>>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>>>>>> mgsloan at gmail.com> >>>>>>>>>> >>>> wrote: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Control.Exception currently lacks a good way to supply extra >>>>>>>>>> >>>>> information along with exceptions. For example, exceptions >>>>>>>>>> could be >>>>>>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], >>>>>>>>>> but we have >>>>>>>>>> >>>>> no generic way to include this information with exceptions. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Proposed Solution >>>>>>>>>> >>>>> ================= >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> The proposed solution is to add a list of >>>>>>>>>> `SomeExceptionInfo` to the >>>>>>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>>>>>> information >>>>>>>>>> >>>>> about the exception. These `ExceptionInfo` instances use a >>>>>>>>>> mechanism >>>>>>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>>>>>> `Exception` type >>>>>>>>>> >>>>> works: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>>>>>> >>>>> SomeExceptionInfo a >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> addExceptionInfo >>>>>>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>>>>>> >>>>> => a -> e -> SomeException >>>>>>>>>> >>>>> addExceptionInfo x (toException -> >>>>>>>>>> SomeExceptionWithInfo e xs) = >>>>>>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that >>>>>>>>>> `Exception` has, >>>>>>>>>> >>>>> because I don't see much point in supporting a hierarchy >>>>>>>>>> for exception >>>>>>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>>>>>> necessary >>>>>>>>>> >>>>> casting. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>>>>>> constraint >>>>>>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to >>>>>>>>>> have a new >>>>>>>>>> >>>>> class for this so that: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>>>>>> >>>>> implementation, for when this extra info is presented to >>>>>>>>>> the user. >>>>>>>>>> >>>>> This function would be invoked by the `show` >>>>>>>>>> implementation for >>>>>>>>>> >>>>> `SomeException`. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> * Types need to opt-in to be usable with >>>>>>>>>> `SomeExceptionInfo`. >>>>>>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>>>>>> acting as >>>>>>>>>> >>>>> such an annotation. Having a class for this allows you >>>>>>>>>> to ask GHCI >>>>>>>>>> >>>>> about all in-scope exception info types via `:info >>>>>>>>>> ExceptionInfo`. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Backwards Compatibility >>>>>>>>>> >>>>> ======================= >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. >>>>>>>>>> This means >>>>>>>>>> >>>>> that this change could be made without breaking code: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ >>>>>>>>>> where >>>>>>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Note that consumers of this do not need to enable >>>>>>>>>> `-XPatternSynonyms`. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Applications >>>>>>>>>> >>>>> ============ >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Callstacks >>>>>>>>>> >>>>> ---------- >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>>>>>> callstacks to >>>>>>>>>> >>>>> exceptions: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> newtype ExceptionCallStack = >>>>>>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: >>>>>>>>>> [String] } >>>>>>>>>> >>>>> deriving Typeable >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>>>>>> >>>>> displayExceptionInfo = unlines . >>>>>>>>>> unExceptionCallStack >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>>>>>> >>>>> throwIOWithStack e = do >>>>>>>>>> >>>>> stack <- currentCallStack >>>>>>>>>> >>>>> if null stack >>>>>>>>>> >>>>> then throwIO e >>>>>>>>>> >>>>> else throwIO (addExceptionInfo >>>>>>>>>> (ExceptionCallStack stack) >>>>>>>>>> >>>>> e) >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> I see little downside for making something like this the >>>>>>>>>> default >>>>>>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>>>>>> `SomeException` >>>>>>>>>> >>>>> would add an additional stacktrace to its annotation, much >>>>>>>>>> like the >>>>>>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, the >>>>>>>>>> >>>>> stacktraces would be associated with the exception, rather >>>>>>>>>> than just >>>>>>>>>> >>>>> listing locations that exceptions were thrown. This makes >>>>>>>>>> it >>>>>>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>>>>>> programs, or in >>>>>>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>>>>>> functioning. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Throwing Exceptions in Handlers >>>>>>>>>> >>>>> ------------------------------- >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Example: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> main = >>>>>>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user >>>>>>>>>> doesn't see it, >>>>>>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This causes >>>>>>>>>> a few >>>>>>>>>> >>>>> issues: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>>>>>> yielded to >>>>>>>>>> >>>>> the user, then the more informative error is lost. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> 2. Callers who expect to catch the "Informative error >>>>>>>>>> message" won't >>>>>>>>>> >>>>> run their handlers for this exception type. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Problem 1 can now easily be resolved by adding some info to >>>>>>>>>> the >>>>>>>>>> >>>>> exception: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>>>>>> >>>>> deriving Typeable >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>>>>>> >>>>> displayExceptionInfo fe = >>>>>>>>>> >>>>> "thrown while handling " ++ >>>>>>>>>> >>>>> displayException (unExceptionCause fe) >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>>>>>> >>>>> where >>>>>>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: >>>>>>>>>> SomeException) -> >>>>>>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>>>>>> >>>>> where >>>>>>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> This implementation of `catch` is written in a >>>>>>>>>> backwards-compatible >>>>>>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>>>>>> still the >>>>>>>>>> >>>>> one that gets rethrown. The "original" exception is >>>>>>>>>> recorded in the >>>>>>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>>>>>> >>>>> `__context__` attribute[3]. This was brought to my >>>>>>>>>> attention in a >>>>>>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket not >>>>>>>>>> suppress >>>>>>>>>> >>>>> the original exception[5]. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> This doesn't directly resolve issue #2, due to this >>>>>>>>>> backwards >>>>>>>>>> >>>>> compatibility. With the earlier example, a `catch` handler >>>>>>>>>> for >>>>>>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it >>>>>>>>>> isn't the >>>>>>>>>> >>>>> exception being rethrown. This can be resolved by having a >>>>>>>>>> variant of >>>>>>>>>> >>>>> catch which instead throws the original exception. This >>>>>>>>>> might be a >>>>>>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>>>>>> `finally`. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Asynchronous Exceptions >>>>>>>>>> >>>>> ----------------------- >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Currently, the only reliable way to catch exceptions, >>>>>>>>>> ignoring async >>>>>>>>>> >>>>> exceptions, is to fork a new thread. This is the approach >>>>>>>>>> used by the >>>>>>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly >>>>>>>>>> that we need >>>>>>>>>> >>>>> to go to such lengths due to the lack of one bit of >>>>>>>>>> information about >>>>>>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this >>>>>>>>>> doesn't enforce >>>>>>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>>>>>> exception. >>>>>>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>>>>>> exception is >>>>>>>>>> >>>>> synchronous or asynchronous. Here's what this would look >>>>>>>>>> like: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> data IsAsync = IsAsync >>>>>>>>>> >>>>> deriving (Typeable, Show) >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>>>>>> >>>>> displayExceptionInfo IsAsync = "thrown >>>>>>>>>> asynchronously" >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> The details of this get a bit tricky: What happens if >>>>>>>>>> `throwIO` is >>>>>>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` >>>>>>>>>> flag set? >>>>>>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>>>>>> interactions >>>>>>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" >>>>>>>>>> async >>>>>>>>>> >>>>> exceptions. Such details are explained in a post by Edsko >>>>>>>>>> de Vries[8] >>>>>>>>>> >>>>> and ghc trac #2558[9]. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Issue: fromException loses info >>>>>>>>>> >>>>> =============================== >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>>>>>> usually form >>>>>>>>>> >>>>> a prism. In other words, when `fromException` yields a >>>>>>>>>> `Just`, you >>>>>>>>>> >>>>> should get the same `SomeException` when using >>>>>>>>>> `toException` on that >>>>>>>>>> >>>>> value. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> For example, >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>>>>>> throwIO ex >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> is equivalent to >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> >>>>>>>>>> throwIO ex >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> However, with exception info added to just `SomeException`, >>>>>>>>>> and no >>>>>>>>>> >>>>> changes to existing `Exception` instances, this >>>>>>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception >>>>>>>>>> type get >>>>>>>>>> >>>>> rethrown with less information. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` >>>>>>>>>> as a field >>>>>>>>>> >>>>> to existing `Exception` instances. This would require the >>>>>>>>>> use of >>>>>>>>>> >>>>> non-default implementations of the `toException` and >>>>>>>>>> `fromException` >>>>>>>>>> >>>>> instances. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> Another approach is to have variants of `catch` and `throw` >>>>>>>>>> which also >>>>>>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> [1] >>>>>>>>>> >>>>> >>>>>>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>>>>>> >>>>> [2] >>>>>>>>>> >>>>> >>>>>>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>>>>>> >>>>> [4] >>>>>>>>>> >>>>> >>>>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>>>>>> >>>>> [5] >>>>>>>>>> >>>>> >>>>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>>>>>> >>>>> [6] https://hackage.haskell.org/package/enclosed-exceptions >>>>>>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>>>>>> >>>>> >>>>>>>>>> >>>>> _______________________________________________ >>>>>>>>>> >>>>> Libraries mailing list >>>>>>>>>> >>>>> Libraries at haskell.org >>>>>>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>>>> >>>>> >>>>>>>>>> >>>> >>>>>>>>>> >>> >>>>>>>>>> >> >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> > _______________________________________________ >>>>>>>>>> > Libraries mailing list >>>>>>>>>> > Libraries at haskell.org >>>>>>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>>>> > >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> Libraries mailing list >>>>>> Libraries at haskell.org >>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> >>>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mgsloan at gmail.com Mon Apr 27 00:07:18 2015 From: mgsloan at gmail.com (Michael Sloan) Date: Sun, 26 Apr 2015 17:07:18 -0700 Subject: Exceptions with Context Re: Proposal: Add exception info In-Reply-To: References: Message-ID: Sure, but the code for "throwWithCallStack" would be the code in my post. Do you disagree that all usages of throw and catch would need to change if we want stack traces? I don't see why changes to the exception machinery are dependent on the new stack trace pieces being in place. DWARF stack traces aren't available on windows, and are only available with -g. Profiling based stack traces are only available with -prof. Implicit location traces require a change to the API which make them problematic for some usecases (edsko found some interesting corners where they interact with unboxed types, can't find the link atm). Point is, we're not going to have a single source for callstacks. Maybe we can have a single type for them. Surely it isn't so hard to come up with a nice datatype to handle rendering these callstacks to the user? Avoiding these sorts of dependencies on in-progress work is one of the reasons I opted for a dynamic / open datatype for the extra info. -Michael On Sun, Apr 26, 2015 at 4:57 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > no, the idea / premise is there'd be a new "throwWithCallStack" and or > "throwWithExtraInfo" > > the POINT here is there no point in doing changes to exception machinery > UNTIL those various new stack trace pieces ?RE PRESENT. > > :) > > On Sun, Apr 26, 2015 at 7:52 PM, Michael Sloan wrote: > >> So, based on discussion in IRC, it's clear that with Davean's proposal >> the thrower would need to call a function which does something like: >> >> stack <- currentCallStack >> throwIO (WithStack stack e) >> >> However, this requires that every thrower change their code if they want >> to provide callstacks. Moreover, every exception handler that wants to >> handle this exception would need to change as well. This would be a >> breaking API change for every library that adds support for callstacks. >> Perhaps this is our only viable option.. >> >> With my proposal, we can have every use of throw provide a callstack, but >> lose the information preservation of fromException. >> >> -Michael >> >> On Tue, Apr 21, 2015 at 9:08 PM, Carter Schonwald < >> carter.schonwald at gmail.com> wrote: >> >>> no michael, Daveans proposal is that we add certain catchWithExtraInfo >>> :: Exception e => IO a -> (ExtraInfo -> e -> IO a ) -> IO a style >>> operations to the exceptions modules, for various choices of "extraInfo" >>> >>> The idea being, NO current exception codes should have to change. Nor >>> does SomeException need to change. >>> i will try to articulate my concerns about your proposed design in more >>> details on the other proposal thread after i've had a bit more sleep and >>> thought about it more >>> >>> >>> On Tue, Apr 21, 2015 at 11:50 PM, Michael Sloan >>> wrote: >>> >>>> Either I am misunderstanding davean's proposal, or you are >>>> misunderstanding mine. Namely: >>>> >>>> * How is his proposal more extensible? His specializes it to just >>>> passing callstack information. >>>> >>>> * I'm not sure exactly how he proposes to change the catch. If it's >>>> changed to always preserve the extra exception info, then this will be a >>>> massive API breakage. >>>> >>>> -Michael >>>> >>>> On Tue, Apr 21, 2015 at 7:23 PM, Carter Schonwald < >>>> carter.schonwald at gmail.com> wrote: >>>> >>>>> hrm, i like this proposal more, and it seems like with some fleshing >>>>> out it can be strictly more extensible yet backwards compatible than >>>>> michael's >>>>> >>>>> I'll need to mull it a bit more before I cast my vote, but this seems >>>>> to sketch out a design that provides the same information, but in a more >>>>> extensible/backwards compatible fashion (at least in a first cut of >>>>> thinking about it) >>>>> >>>>> (i'm splitting this into a new thread so the discussions dont get >>>>> mixed up) >>>>> >>>>> On Tue, Apr 21, 2015 at 9:40 PM, davean wrote: >>>>> >>>>>> So, I've had a number of issues with exceptions. This has been one of >>>>>> them. I don't really like this proposal as it stands though as it seems to >>>>>> make catch a specific exception with said extra info more difficult. >>>>>> >>>>>> This is data Control.Exception can move around on its own though, >>>>>> right? The problem really isn't passing it internal, we could just make a >>>>>> (Stack, SomeException) tuple just fine, in theory I think (I'll admit I've >>>>>> not actually reviewed the code, and this isn't meant as a complete proposal >>>>>> but more a thought experiment). The problem is code handling the data and >>>>>> working with old code while not losing any of the power of the current >>>>>> system. >>>>>> >>>>>> So we start with: catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>> >>>>>> Now this proposal allows: catch :: IO a -> (SomeException -> IO a) -> >>>>>> IO a >>>>>> If we want access to the new information, but that's not really >>>>>> satisfactory. >>>>>> >>>>>> Real code regularly wants to (picking an arbitrary instance of >>>>>> Exception) do: catch :: IO a -> (IOError -> IO a) -> IO a >>>>>> only we still want new data. >>>>>> >>>>>> Now one could do something like: catch :: IO a -> (Stack -> IOError >>>>>> -> IO a) -> IO a >>>>>> but that is not very upgradable and it breaks existing code. >>>>>> >>>>>> But this is just a matter of requesting information, so one could do >>>>>> something like: catch :: IO a -> (WithStack IOError -> IO a) -> IO a >>>>>> where: data WithStack e = WithStack Stack e >>>>>> Or maybe one just addes: catchWithContext :: Exception e => IO a -> >>>>>> (Context -> e -> IO a) -> IO a >>>>>> Or: catchWithContext :: Exception => IO a -> (Context e -> IO a) -> >>>>>> IO a >>>>>> >>>>>> Now existing code continues to run and we can feed our exception >>>>>> handlers the data they want, even when we want some specific exception >>>>>> instead of just any exception. >>>>>> >>>>>> Now that still leave a hole in what I want out of exceptions. We're >>>>>> still short of programmatic interrogating them, or even telling what the >>>>>> exception was if we didn't expect it! >>>>>> >>>>>> Consider AssertionFailed >>>>>> . >>>>>> Its show instance is "showsPrec _ (AssertionFailed err) = showString err", >>>>>> so if we print out the SomeException, we get whatever string is in >>>>>> AssertionFailed. Which is great if that string makes sense. But you see >>>>>> that on your console and its a bit baffling if it doesn't. It could even be >>>>>> a lie, I can make that say something that looks like its a different >>>>>> exception. We can use the Typeable instance so the program can tell them >>>>>> apart at least though. Which works as long as the exception is >>>>>> single-constructor, or has a well-behaved show instance. What if we come >>>>>> across a monstrosity like >>>>>> http://hackage.haskell.org/package/http-conduit-2.1.5/docs/Network-HTTP-Conduit.html#g:12 >>>>>> and it doesn't have a nice show instance that says which on it is? If >>>>>> Exception added a Data constraint we could actually pull apart these >>>>>> exceptions and start to make proper sense of them reliably. >>>>>> >>>>>> Once you have that there are quite a few useful things you can do >>>>>> with the exceptions you didn't expect. Currently you could only do them by >>>>>> enumerating every possible exception which of course doesn't work for the >>>>>> unexpected. >>>>>> >>>>>> On Tue, Apr 21, 2015 at 6:24 PM, Michael Sloan >>>>>> wrote: >>>>>> >>>>>>> No, this proposal is not specifically about stack traces, that is >>>>>>> just one of the usecases. Instead, this is about a general mechanism for >>>>>>> including extra information with exceptions. The core of this proposal is >>>>>>> still relevant even if the behavior of error / throw / throwTo / etc remain >>>>>>> unchanged. >>>>>>> >>>>>>> I'm not familiar with how the new dwarf stuff will interact with >>>>>>> throwing / displaying exceptions. It seems like this would require having >>>>>>> the debugger break at the throw site, and exceptions would still lack stack >>>>>>> traces. Having informative stack traces is quite orthogonal to having a >>>>>>> good place to store them. >>>>>>> >>>>>>> Note that in my original proposal text I mentioned that this is >>>>>>> agnostic of the particular source of the stack trace. In particular, this >>>>>>> could be used with a profiling stack trace, implicit callstack, or, indeed, >>>>>>> these traces via dwarf. >>>>>>> >>>>>>> -Michael >>>>>>> >>>>>>> On Tue, Apr 21, 2015 at 3:06 PM, Carter Schonwald < >>>>>>> carter.schonwald at gmail.com> wrote: >>>>>>> >>>>>>>> On a more important note: assuming ghc 7.12 has support for >>>>>>>> informative stack traces via dwarf by default, wouldn't that eliminate the >>>>>>>> need for this proposal? Namely : there perhaps should be some reasonable >>>>>>>> way to talk about concatting stack traces perhaps? >>>>>>>> >>>>>>>> Phrased differently: how is the info that should perhaps be in >>>>>>>> informative stack traces not subsuming the info of this proposal? >>>>>>>> >>>>>>>> >>>>>>>> On Tuesday, April 21, 2015, Michael Sloan >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Ah, but it looks like Niklas does have a patch which adds implicit >>>>>>>>> locations to such functions: https://phabricator.haskell.org/D861 >>>>>>>>> >>>>>>>>> However, there are some issues with changing the API of these >>>>>>>>> functions: https://phabricator.haskell.org/D861#23250 >>>>>>>>> >>>>>>>>> (as mentioned in the "Backporting srcLoc to the GHC 7.10 branch" >>>>>>>>> thread) >>>>>>>>> >>>>>>>>> On Tue, Apr 21, 2015 at 2:04 PM, Michael Sloan >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> Hmm, that patch doesn't appear to add stack traces to >>>>>>>>>> 'Prelude.error', which is what Carter wants here. Also, I think it would >>>>>>>>>> be done with profiling callstacks rather than implicit callstacks. But >>>>>>>>>> it's certainly also useful to have functions which do the same with >>>>>>>>>> implicit callstacks! >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On Tue, Apr 21, 2015 at 1:55 PM, Evan Laforge >>>>>>>>>> wrote: >>>>>>>>>> >>>>>>>>>>> Maybe I'm missing something, but isn't this already implemented? >>>>>>>>>>> >>>>>>>>>>> https://phabricator.haskell.org/D578 >>>>>>>>>>> >>>>>>>>>>> On Tue, Apr 21, 2015 at 1:37 PM, Michael Sloan < >>>>>>>>>>> mgsloan at gmail.com> wrote: >>>>>>>>>>> > On Thu, Apr 16, 2015 at 8:08 PM, Carter Schonwald >>>>>>>>>>> > wrote: >>>>>>>>>>> >> >>>>>>>>>>> >> if you can patch prelude error to include stack traces, i >>>>>>>>>>> will owe you a >>>>>>>>>>> >> >=1 beer each at the next two icfps. Thats all i want for >>>>>>>>>>> christmas. :) >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> > Sounds good! No promises, but I'll be giving this a try >>>>>>>>>>> soon. Looking >>>>>>>>>>> > forward to ICFP beers either way :D >>>>>>>>>>> > >>>>>>>>>>> >> i can't speak for how a different patch might work out, >>>>>>>>>>> because thats not >>>>>>>>>>> >> what I'd tried at the time. If you have a go, please share >>>>>>>>>>> the results! >>>>>>>>>>> >> -Carter >>>>>>>>>>> >> >>>>>>>>>>> >> On Wed, Apr 15, 2015 at 12:22 AM, Michael Sloan < >>>>>>>>>>> mgsloan at gmail.com> wrote: >>>>>>>>>>> >>> >>>>>>>>>>> >>> Hi Carter! >>>>>>>>>>> >>> >>>>>>>>>>> >>> Interesting! This thread, right? >>>>>>>>>>> >>> >>>>>>>>>>> https://mail.haskell.org/pipermail/libraries/2014-December/024429.html >>>>>>>>>>> >>> >>>>>>>>>>> >>> I haven't tried this as a patch to base, but I'm certain >>>>>>>>>>> that the core of >>>>>>>>>>> >>> the proposal has no extra dependencies. Note that the >>>>>>>>>>> proposal isn't about >>>>>>>>>>> >>> stack traces in particular - that's just one application of >>>>>>>>>>> being able to >>>>>>>>>>> >>> throw exceptions with extra information. >>>>>>>>>>> >>> >>>>>>>>>>> >>> Even if `throwTo` isn't modified to throw exceptions with >>>>>>>>>>> stack traces, >>>>>>>>>>> >>> this functionality could be provided outside of >>>>>>>>>>> `Control.Exception` (though, >>>>>>>>>>> >>> that does seem like the right place to put it). I'm >>>>>>>>>>> surprised that the >>>>>>>>>>> >>> circularity was so problematic, though. Why isn't it >>>>>>>>>>> sufficient to have an >>>>>>>>>>> >>> hs-boot file for `GHC.Stack`, which exports >>>>>>>>>>> `currentCallStack`? >>>>>>>>>>> >>> >>>>>>>>>>> >>> -Michael >>>>>>>>>>> >>> >>>>>>>>>>> >>> On Tue, Apr 14, 2015 at 7:55 PM, Carter Schonwald >>>>>>>>>>> >>> wrote: >>>>>>>>>>> >>>> >>>>>>>>>>> >>>> Hey Michael, >>>>>>>>>>> >>>> I actually proposed something along these lines that got >>>>>>>>>>> OK'd by >>>>>>>>>>> >>>> libraries early this past fall, the main challenge we hit >>>>>>>>>>> was actually doing >>>>>>>>>>> >>>> the enginering to add the stack traces to exceptions! >>>>>>>>>>> theres some nasty >>>>>>>>>>> >>>> module cycles in base that happen when you try to weave >>>>>>>>>>> things around so >>>>>>>>>>> >>>> that the standard error "message here" call includes some >>>>>>>>>>> stack trace info. >>>>>>>>>>> >>>> Have you tried to do that simple starter patch to base? >>>>>>>>>>> >>>> >>>>>>>>>>> >>>> Chris Allen and I spent like 2 days trying to get it to >>>>>>>>>>> work and just >>>>>>>>>>> >>>> gave up because of the cycles. We (and others) would >>>>>>>>>>> probably love some >>>>>>>>>>> >>>> headway on that front. >>>>>>>>>>> >>>> >>>>>>>>>>> >>>> Theres also some in progress work to use the dwarf >>>>>>>>>>> debugging info data >>>>>>>>>>> >>>> in >7.10 to provide useful stack traces in the default >>>>>>>>>>> builds for GHC afaik, >>>>>>>>>>> >>>> 'cause the stack trace functionality you're pointing at >>>>>>>>>>> currenlty only work >>>>>>>>>>> >>>> on profiled builds >>>>>>>>>>> >>>> >>>>>>>>>>> >>>> cheers >>>>>>>>>>> >>>> -Carter >>>>>>>>>>> >>>> >>>>>>>>>>> >>>> On Tue, Apr 14, 2015 at 2:38 PM, Michael Sloan < >>>>>>>>>>> mgsloan at gmail.com> >>>>>>>>>>> >>>> wrote: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Control.Exception currently lacks a good way to supply >>>>>>>>>>> extra >>>>>>>>>>> >>>>> information along with exceptions. For example, >>>>>>>>>>> exceptions could be >>>>>>>>>>> >>>>> thrown along with their callstack[1] or implicit stack[2], >>>>>>>>>>> but we have >>>>>>>>>>> >>>>> no generic way to include this information with exceptions. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Proposed Solution >>>>>>>>>>> >>>>> ================= >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> The proposed solution is to add a list of >>>>>>>>>>> `SomeExceptionInfo` to the >>>>>>>>>>> >>>>> `SomeException` datatype. This list stores additional >>>>>>>>>>> information >>>>>>>>>>> >>>>> about the exception. These `ExceptionInfo` instances use >>>>>>>>>>> a mechanism >>>>>>>>>>> >>>>> which is pretty much identical to the dynamic way the >>>>>>>>>>> `Exception` type >>>>>>>>>>> >>>>> works: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> data SomeException = forall e . Exception e => >>>>>>>>>>> >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>>>>>>>> >>>>> SomeExceptionInfo a >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> class Typeable a => ExceptionInfo a where >>>>>>>>>>> >>>>> displayExceptionInfo :: a -> String >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> addExceptionInfo >>>>>>>>>>> >>>>> :: (ExceptionInfo a, Exception e) >>>>>>>>>>> >>>>> => a -> e -> SomeException >>>>>>>>>>> >>>>> addExceptionInfo x (toException -> >>>>>>>>>>> SomeExceptionWithInfo e xs) = >>>>>>>>>>> >>>>> SomeExceptionWithInfo e (SomeExceptionInfo x : xs) >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> `ExceptionInfo` lacks the to / from functions that >>>>>>>>>>> `Exception` has, >>>>>>>>>>> >>>>> because I don't see much point in supporting a hierarchy >>>>>>>>>>> for exception >>>>>>>>>>> >>>>> info. The `Typeable` superclass constraint supplies the >>>>>>>>>>> necessary >>>>>>>>>>> >>>>> casting. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> `SomeExceptionInfo` could validly instead just use the >>>>>>>>>>> constraint >>>>>>>>>>> >>>>> `(Typeable a, Show a)`. However, I believe it's good to >>>>>>>>>>> have a new >>>>>>>>>>> >>>>> class for this so that: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> * The user can specify a custom `displayExceptionInfo` >>>>>>>>>>> >>>>> implementation, for when this extra info is presented to >>>>>>>>>>> the user. >>>>>>>>>>> >>>>> This function would be invoked by the `show` >>>>>>>>>>> implementation for >>>>>>>>>>> >>>>> `SomeException`. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> * Types need to opt-in to be usable with >>>>>>>>>>> `SomeExceptionInfo`. >>>>>>>>>>> >>>>> Similarly to exceptions, I imagine that a type with a >>>>>>>>>>> >>>>> `ExceptionInfo` instance won't be used for anything but >>>>>>>>>>> acting as >>>>>>>>>>> >>>>> such an annotation. Having a class for this allows you >>>>>>>>>>> to ask GHCI >>>>>>>>>>> >>>>> about all in-scope exception info types via `:info >>>>>>>>>>> ExceptionInfo`. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Backwards Compatibility >>>>>>>>>>> >>>>> ======================= >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> GHC 7.10 adds support for bidirectional pattern synonyms. >>>>>>>>>>> This means >>>>>>>>>>> >>>>> that this change could be made without breaking code: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> pattern SomeException x <- SomeExceptionWithInfo x _ >>>>>>>>>>> where >>>>>>>>>>> >>>>> SomeException x = SomeExceptionWithInfo x [] >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Note that consumers of this do not need to enable >>>>>>>>>>> `-XPatternSynonyms`. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Applications >>>>>>>>>>> >>>>> ============ >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Callstacks >>>>>>>>>>> >>>>> ---------- >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> As mentioned at the beginning, this can be used to add >>>>>>>>>>> callstacks to >>>>>>>>>>> >>>>> exceptions: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> newtype ExceptionCallStack = >>>>>>>>>>> >>>>> ExceptionCallStack { unExceptionCallStack :: >>>>>>>>>>> [String] } >>>>>>>>>>> >>>>> deriving Typeable >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> instance ExceptionInfo ExceptionCallStack where >>>>>>>>>>> >>>>> displayExceptionInfo = unlines . >>>>>>>>>>> unExceptionCallStack >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> throwIOWithStack :: Exception e => e -> IO a >>>>>>>>>>> >>>>> throwIOWithStack e = do >>>>>>>>>>> >>>>> stack <- currentCallStack >>>>>>>>>>> >>>>> if null stack >>>>>>>>>>> >>>>> then throwIO e >>>>>>>>>>> >>>>> else throwIO (addExceptionInfo >>>>>>>>>>> (ExceptionCallStack stack) >>>>>>>>>>> >>>>> e) >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> I see little downside for making something like this the >>>>>>>>>>> default >>>>>>>>>>> >>>>> implementation `throwIO`. Each rethrowing of the >>>>>>>>>>> `SomeException` >>>>>>>>>>> >>>>> would add an additional stacktrace to its annotation, much >>>>>>>>>>> like the >>>>>>>>>>> >>>>> output of `+RTS -xc`. Unlike this debug output, though, >>>>>>>>>>> the >>>>>>>>>>> >>>>> stacktraces would be associated with the exception, rather >>>>>>>>>>> than just >>>>>>>>>>> >>>>> listing locations that exceptions were thrown. This makes >>>>>>>>>>> it >>>>>>>>>>> >>>>> tractable to debug exceptions that occur in concurrent >>>>>>>>>>> programs, or in >>>>>>>>>>> >>>>> programs which frequently throw exceptions during normal >>>>>>>>>>> functioning. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Throwing Exceptions in Handlers >>>>>>>>>>> >>>>> ------------------------------- >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Example: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> main = >>>>>>>>>>> >>>>> throwIO InformativeErrorMessage `finally` >>>>>>>>>>> >>>>> throwIO ObscureCleanupIssue >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> While `InformativeErrorMessage` got thrown, the user >>>>>>>>>>> doesn't see it, >>>>>>>>>>> >>>>> since `ObscureCleanupIssue` is thrown instead. This >>>>>>>>>>> causes a few >>>>>>>>>>> >>>>> issues: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> 1. If the exception is handled by the default handler and >>>>>>>>>>> yielded to >>>>>>>>>>> >>>>> the user, then the more informative error is lost. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> 2. Callers who expect to catch the "Informative error >>>>>>>>>>> message" won't >>>>>>>>>>> >>>>> run their handlers for this exception type. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Problem 1 can now easily be resolved by adding some info >>>>>>>>>>> to the >>>>>>>>>>> >>>>> exception: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> data ExceptionCause = ExceptionCause >>>>>>>>>>> >>>>> { unExceptionCause :: SomeException } >>>>>>>>>>> >>>>> deriving Typeable >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> instance ExceptionInfo ExceptionCause where >>>>>>>>>>> >>>>> displayExceptionInfo fe = >>>>>>>>>>> >>>>> "thrown while handling " ++ >>>>>>>>>>> >>>>> displayException (unExceptionCause fe) >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> catch :: Exception e => IO a -> (e -> IO a) -> IO a >>>>>>>>>>> >>>>> catch f g = f `oldCatch` handler >>>>>>>>>>> >>>>> where >>>>>>>>>>> >>>>> handler ex = g ex `oldCatch` \(ex' :: >>>>>>>>>>> SomeException) -> >>>>>>>>>>> >>>>> throwIO (addExceptionInfo info ex') >>>>>>>>>>> >>>>> where >>>>>>>>>>> >>>>> info = ExceptionCause (toException ex) >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> This implementation of `catch` is written in a >>>>>>>>>>> backwards-compatible >>>>>>>>>>> >>>>> way, such that the exception thrown during finalization is >>>>>>>>>>> still the >>>>>>>>>>> >>>>> one that gets rethrown. The "original" exception is >>>>>>>>>>> recorded in the >>>>>>>>>>> >>>>> added info. This is the same approach used by Python 3's >>>>>>>>>>> >>>>> `__context__` attribute[3]. This was brought to my >>>>>>>>>>> attention in a >>>>>>>>>>> >>>>> post by Mike Meyer[4], in a thread about having bracket >>>>>>>>>>> not suppress >>>>>>>>>>> >>>>> the original exception[5]. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> This doesn't directly resolve issue #2, due to this >>>>>>>>>>> backwards >>>>>>>>>>> >>>>> compatibility. With the earlier example, a `catch` >>>>>>>>>>> handler for >>>>>>>>>>> >>>>> `InformativeErrorMessage` won't be invoked, because it >>>>>>>>>>> isn't the >>>>>>>>>>> >>>>> exception being rethrown. This can be resolved by having >>>>>>>>>>> a variant of >>>>>>>>>>> >>>>> catch which instead throws the original exception. This >>>>>>>>>>> might be a >>>>>>>>>>> >>>>> good default for finalization handlers like `bracket` and >>>>>>>>>>> `finally`. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Asynchronous Exceptions >>>>>>>>>>> >>>>> ----------------------- >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Currently, the only reliable way to catch exceptions, >>>>>>>>>>> ignoring async >>>>>>>>>>> >>>>> exceptions, is to fork a new thread. This is the approach >>>>>>>>>>> used by the >>>>>>>>>>> >>>>> enclosed-exceptions[6] package. I think it's quite ugly >>>>>>>>>>> that we need >>>>>>>>>>> >>>>> to go to such lengths due to the lack of one bit of >>>>>>>>>>> information about >>>>>>>>>>> >>>>> the exception! This would resolve ghc trac #5902[7]. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> base-4.7 added the `SomeAsyncException` type, but this >>>>>>>>>>> doesn't enforce >>>>>>>>>>> >>>>> anything. Any exception can be thrown as a sync or async >>>>>>>>>>> exception. >>>>>>>>>>> >>>>> Instead, we ought to have a reliable way to know if an >>>>>>>>>>> exception is >>>>>>>>>>> >>>>> synchronous or asynchronous. Here's what this would look >>>>>>>>>>> like: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> data IsAsync = IsAsync >>>>>>>>>>> >>>>> deriving (Typeable, Show) >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> instance ExceptionInfo IsAsync where >>>>>>>>>>> >>>>> displayExceptionInfo IsAsync = "thrown >>>>>>>>>>> asynchronously" >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> throwTo :: Exception e => ThreadId -> e -> IO () >>>>>>>>>>> >>>>> throwTo tid = oldThrowTo tid . addExceptionInfo IsAsync >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> The details of this get a bit tricky: What happens if >>>>>>>>>>> `throwIO` is >>>>>>>>>>> >>>>> used to rethrow a `SomeException` which has this `IsAsync` >>>>>>>>>>> flag set? >>>>>>>>>>> >>>>> I'm going to leave out my thoughts on this for now as the >>>>>>>>>>> interactions >>>>>>>>>>> >>>>> between unsafePerformIO and the concept of "rethrowing" >>>>>>>>>>> async >>>>>>>>>>> >>>>> exceptions. Such details are explained in a post by Edsko >>>>>>>>>>> de Vries[8] >>>>>>>>>>> >>>>> and ghc trac #2558[9]. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Issue: fromException loses info >>>>>>>>>>> >>>>> =============================== >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> I can think of one main non-ideal aspect of this proposal: >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Currently, the `toException` and `fromException` methods >>>>>>>>>>> usually form >>>>>>>>>>> >>>>> a prism. In other words, when `fromException` yields a >>>>>>>>>>> `Just`, you >>>>>>>>>>> >>>>> should get the same `SomeException` when using >>>>>>>>>>> `toException` on that >>>>>>>>>>> >>>>> value. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> For example, >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> fail "testing 1 2 3" `catch` \(ex :: SomeException) -> >>>>>>>>>>> throwIO ex >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> is equivalent to >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> fail "testing 3 4 5" `catch` \(ex :: IOError) -> >>>>>>>>>>> throwIO ex >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> However, with exception info added to just >>>>>>>>>>> `SomeException`, and no >>>>>>>>>>> >>>>> changes to existing `Exception` instances, this >>>>>>>>>>> >>>>> doesn't hold. Exceptions caught as a specific exception >>>>>>>>>>> type get >>>>>>>>>>> >>>>> rethrown with less information. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> One resolution to this is be to add `[SomeExceptionInfo]` >>>>>>>>>>> as a field >>>>>>>>>>> >>>>> to existing `Exception` instances. This would require the >>>>>>>>>>> use of >>>>>>>>>>> >>>>> non-default implementations of the `toException` and >>>>>>>>>>> `fromException` >>>>>>>>>>> >>>>> instances. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> Another approach is to have variants of `catch` and >>>>>>>>>>> `throw` which also >>>>>>>>>>> >>>>> pass around the `[SomeExceptionInfo]`. >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> [1] >>>>>>>>>>> >>>>> >>>>>>>>>>> https://hackage.haskell.org/package/base-4.8.0.0/docs/GHC-Stack.html#currentCallStack >>>>>>>>>>> >>>>> [2] >>>>>>>>>>> >>>>> >>>>>>>>>>> https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations >>>>>>>>>>> >>>>> [3] https://www.python.org/dev/peps/pep-3134/ >>>>>>>>>>> >>>>> [4] >>>>>>>>>>> >>>>> >>>>>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114987.html >>>>>>>>>>> >>>>> [5] >>>>>>>>>>> >>>>> >>>>>>>>>>> https://mail.haskell.org/pipermail/haskell-cafe/2014-July/114986.html >>>>>>>>>>> >>>>> [6] >>>>>>>>>>> https://hackage.haskell.org/package/enclosed-exceptions >>>>>>>>>>> >>>>> [7] https://ghc.haskell.org/trac/ghc/ticket/5902 >>>>>>>>>>> >>>>> [8] http://www.edsko.net/2013/06/11/throwTo/ >>>>>>>>>>> >>>>> [9] https://ghc.haskell.org/trac/ghc/ticket/2558 >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>>> _______________________________________________ >>>>>>>>>>> >>>>> Libraries mailing list >>>>>>>>>>> >>>>> Libraries at haskell.org >>>>>>>>>>> >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>>>>> >>>>> >>>>>>>>>>> >>>> >>>>>>>>>>> >>> >>>>>>>>>>> >> >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> > _______________________________________________ >>>>>>>>>>> > Libraries mailing list >>>>>>>>>>> > Libraries at haskell.org >>>>>>>>>>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>>>>>> > >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>> >>>>>>> _______________________________________________ >>>>>>> Libraries mailing list >>>>>>> Libraries at haskell.org >>>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gershomb at gmail.com Mon Apr 27 02:03:50 2015 From: gershomb at gmail.com (Gershom B) Date: Sun, 26 Apr 2015 22:03:50 -0400 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: Here is an idea to cut though a lot of the confusion in this discussion. It seems to me that _all_ ideas under discussion can be written as libraries, external to the RTS and external to GHC base. Of course, this means that all the functions in base won?t take advantage of these ideas, and won?t throw exceptions with any additional info. However, it should be the case that we can take e.g. Michael?s proposal, turn it into an experimental library, including exports of a few key base functions but now using this new exception approach, and just toss it on hackage. At that point, people can download and experiment with it, or attempt to modify it and hack on it to try out some variations. This isn?t the same as trying it all out _in base_ but it will let people experiment with various approaches, and come to a clearer conclusion on what the tradeoffs are. After some time where people can try the various approaches as experiments, we can revisit a discussion on which, if any, should move into the default base implementation. ?Gershom On April 26, 2015 at 7:45:37 PM, John Wiegley (johnw at newartisans.com) wrote: > >>>>> Edward Kmett writes: > > > That said, I'd very much rather err on the side of doing nothing rather than > > do the wrong thing here. > > > We'll be stuck with it for a long time. > > I agree with Edward's sentiments. > > John > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > From allbery.b at gmail.com Mon Apr 27 02:09:37 2015 From: allbery.b at gmail.com (Brandon Allbery) Date: Mon, 27 Apr 2015 02:09:37 +0000 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Mon, Apr 27, 2015 at 2:03 AM, Gershom B wrote: > However, it should be the case that we can take e.g. Michael?s proposal, > turn it into an experimental library, including exports of a few key base > functions but now using this new exception approach, and just toss it on > hackage. At that point, people can download and experiment with it, or > attempt to modify it and hack on it to try out some variations. This isn?t > the same as trying it all out _in base_ but it will let people experiment > with various approaches, and come to a clearer conclusion on what the > tradeoffs are. After some time where people can try the various approaches > as experiments, we can revisit a discussion on which, if any, should move > into the default base implementation. Maybe include an alternative Prelude, (mostly?) compatible with the base one but using the new functions. -- brandon s allbery kf8nh sine nomine associates allbery.b at gmail.com ballbery at sinenomine.net unix, openafs, kerberos, infrastructure, xmonad http://sinenomine.net -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg.grenrus at iki.fi Mon Apr 27 06:36:04 2015 From: oleg.grenrus at iki.fi (Oleg Grenrus) Date: Mon, 27 Apr 2015 09:36:04 +0300 Subject: Maintainship of edit-distance and lattices In-Reply-To: References: <0A070966-4476-4A82-A16C-65C692D9DA50@iki.fi> <440AF82D-A958-4927-9F63-F4A634F10581@iki.fi> Message-ID: <8DEE5C2D-0EFC-4042-939D-8081AADCF36D@iki.fi> Hi, to make it clear. I don?t want to drastically change lattices or edit-distance; I use them and they are ok, wouldn?t use otherwise. There are only few things on top of my mind, I could make as a maintainer: - add Eq, Ord, Show etc instances to data types there: http://hackage.haskell.org/package/lattices-1.2.1.1/docs/Algebra-Lattice-Dropped.html - make point-wise instances for Lattice b => Lattice (a -> b) (same way as with Monoid) - write tests edit-distance would benefit from `cabal test` too (there are tests, but as executables). Then they?ll be run by stackage builds. - Oleg > On 26 Apr 2015, at 21:19, davean wrote: > > I use http://hackage.haskell.org/package/lattices heavily so I care what becomes of it, but haven't had issues with it. > > I too have noticed he's not around though with his other packages. > > On Sun, Apr 26, 2015 at 1:22 PM, Oleg Grenrus wrote: > Opened a trustee issue: > > https://github.com/haskell-infra/hackage-trustees/issues/31 > > I have no hurry with lattices, as it compiles with 7.10 ok. > > - Oleg > >> On 26 Apr 2015, at 20:06, Adam Bergmark wrote: >> >> Hi Oleg, >> >> edit-distance is also being tracked here: https://github.com/haskell-infra/hackage-trustees/issues/19 >> Please update it with a link to this discussion. >> >> You can also open a new issue for lattices so we can keep track of the progress for it as well. >> >> >> On Sun, Apr 26, 2015 at 5:50 PM, Sean Leather wrote: >> Hi Oleg, >> >> On Sun, Apr 26, 2015 at 3:52 PM, Oleg Grenrus wrote: >> I?d like to help with maintaining of mentioned packages: >> - http://hackage.haskell.org/package/edit-distance >> - http://hackage.haskell.org/package/lattices >> >> Max doesn?t seem to be active on GitHub, there are >> - a PR to edit-distance fixing the build on GHC 7.10, open for 26 days: https://github.com/batterseapower/edit-distance/pull/3 >> >> I have a pull request open for over a year. It was minor, so I didn't follow up on it: >> https://github.com/batterseapower/edit-distance/pull/2 >> >> - a PR to lattices opened at Jan 8 2015 (open for over 3 months already) https://github.com/batterseapower/lattices/pull/3 >> >> I could take over the maintainership of the packages, if Max doesn?t respond in two weeks >> >> There have been other, similar requests to Max within the last 2 years or so, and I don't think there were any responses. I would be in favor of somebody else taking over as maintainer. >> >> Regards, >> Sean >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 842 bytes Desc: Message signed with OpenPGP using GPGMail URL: From k-bx at k-bx.com Mon Apr 27 08:30:32 2015 From: k-bx at k-bx.com (Kostiantyn Rybnikov) Date: Mon, 27 Apr 2015 11:30:32 +0300 Subject: Ord for partially ordered sets In-Reply-To: References: Message-ID: While this is a bit off-topic, I'd like to add my 5 cents that often adding instances for common type-classes might be "bad" even when it's totally defined for all values, one example is a Monoid instance for HashMap. So, I'd say that if you might be in doubt -- it's better to not add instance at all, since your users have no ability to remove it from their projects (or redefine). 26 ????. 2015 04:10 "wren romano" ????: > On Fri, Apr 24, 2015 at 9:06 AM, Ivan Lazar Miljenovic > wrote: > > What is the validity of defining an Ord instance for types for which > > mathematically the `compare` function is partially ordered? > > Defining Ord instances for types which are not totally ordered is *wrong*. > > For example, due to the existence of NaN values, Double/Float are not > totally ordered and therefore their Ord instances are buggy. In my > logfloat package I have to explicitly add checks to work around the > issues introduced by the buggy Ord Double instance. This is why I > introduced the PartialOrd class, and I'm not the first one to create > such a class. We really ought to have an official PartialOrd class as > part of base/Prelude. The only question is whether to use Maybe > Ordering or a specially defined PartialOrdering type (the latter > optimizing for space and pointer indirection; the former optimizing > for reducing code duplication for manipulating the > Ordering/PartialOrdering types). > > -- > Live well, > ~wren > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From simonpj at microsoft.com Mon Apr 27 09:45:53 2015 From: simonpj at microsoft.com (Simon Peyton Jones) Date: Mon, 27 Apr 2015 09:45:53 +0000 Subject: Maintainship of edit-distance and lattices In-Reply-To: References: <0A070966-4476-4A82-A16C-65C692D9DA50@iki.fi> Message-ID: <70a6abd140ee4705a96d5bdb201fdec6@DB4PR30MB030.064d.mgd.msft.net> There have been other, similar requests to Max within the last 2 years or so, and I don't think there were any responses. I would be in favor of somebody else taking over as maintainer. As I understand it, after a period of tremendous productivity, Max is no longer active in the Haskell community. I doubt that he would be offended if you took over maintainership. On the contrary, it would be a way of keeping his past contributions up to date and useful to today?s community. Simon From: Libraries [mailto:libraries-bounces at haskell.org] On Behalf Of Sean Leather Sent: 26 April 2015 16:51 To: Oleg Grenrus Cc: libraries; Max Bolingbroke Subject: Re: Maintainship of edit-distance and lattices Hi Oleg, On Sun, Apr 26, 2015 at 3:52 PM, Oleg Grenrus wrote: I?d like to help with maintaining of mentioned packages: - http://hackage.haskell.org/package/edit-distance - http://hackage.haskell.org/package/lattices Max doesn?t seem to be active on GitHub, there are - a PR to edit-distance fixing the build on GHC 7.10, open for 26 days: https://github.com/batterseapower/edit-distance/pull/3 I have a pull request open for over a year. It was minor, so I didn't follow up on it: https://github.com/batterseapower/edit-distance/pull/2 - a PR to lattices opened at Jan 8 2015 (open for over 3 months already) https://github.com/batterseapower/lattices/pull/3 I could take over the maintainership of the packages, if Max doesn?t respond in two weeks There have been other, similar requests to Max within the last 2 years or so, and I don't think there were any responses. I would be in favor of somebody else taking over as maintainer. Regards, Sean -------------- next part -------------- An HTML attachment was scrubbed... URL: From greg at gregweber.info Mon Apr 27 13:01:37 2015 From: greg at gregweber.info (Greg Weber) Date: Mon, 27 Apr 2015 06:01:37 -0700 Subject: Proposal: Add exception info In-Reply-To: References: Message-ID: On Sun, Apr 26, 2015 at 1:26 PM, Michael Sloan wrote: > Right, we have a choice between making a breaking change towards a more > standard API, or using a rather new language extension (bidirectional > pattern synonyms) to avoid breakage. > That is not what I was trying to get at in my feedback. Using pattern synonyms to maintain backwards compatibility with the current form is independent of what many variations of the new form look like. > On Thu, Apr 23, 2015 at 6:30 AM, Greg Weber wrote: > >> >> >> On Tue, Apr 21, 2015 at 1:55 PM, Michael Sloan wrote: >> >>> >>> On Tue, Apr 21, 2015 at 8:23 AM, Greg Weber wrote: >>> >>>> >>>> On Tue, Apr 14, 2015 at 11:38 AM, Michael Sloan >>>> wrote: >>>> >>>>> data SomeException = forall e . Exception e => >>>>> SomeExceptionWithInfo e [SomeExceptionInfo] >>>>> >>>>> data SomeExceptionInfo = forall a . ExceptionInfo a => >>>>> SomeExceptionInfo a >>>> >>>> >>>> Is it necessary for SomeExceptionWithInfo to have a list of a forall >>>> data type? >>>> Are Exceptions really that mysterious, or can we more concretely >>>> describe the information that should be attached to an exception? >>>> >>>> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >>>> >>> >>> I did consider this option, but I think as soon as a fixed set is >>> selected, someone's going to put something else in it. Usually we wouldn't >>> want to use such a 'dynamic' mechanism in Haskell, but it's appropriate for >>> something so global as the type used to throw exceptions. >>> >> >> The usual approach is to use information hiding. We are being rescued by >> pattern synonyms right now because the constructor is directly exported. >> Why not hide what needs to be hidden to make this more extensible and use >> smart constructors, etc?. >> >> >>> >>> >>>> I am still open to the idea of adding a forall data scratchpad, but can >>>> we at least try to specify some standard fields? >>>> >>>> SomeExceptionWithInfo e IsAsync CallStack ImplicitStack >>>> [SomeExceptionInfo] >>>> >>> >>> This is an interesting idea. I particularly see value in having >>> 'IsAsync' be a part of the Exception. This is because `throwIO` / `throw` >>> would need to set this to False when rethrowing async exceptions. >>> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From zl29ah at gmail.com Tue Apr 28 22:47:23 2015 From: zl29ah at gmail.com (Sergey Alirzaev) Date: Wed, 29 Apr 2015 01:47:23 +0300 Subject: monad-peel takeover Message-ID: <20150429014723.7a3deda4@gmail.com> I'd like to take the maintenance of monad-peel as it's currently broken and Anders seems unavailable. -- () ascii ribbon campaign - against html mail /\ http://arc.pasp.de/ - against proprietary attachments -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From michael at snoyman.com Wed Apr 29 04:20:44 2015 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 29 Apr 2015 04:20:44 +0000 Subject: monad-peel takeover In-Reply-To: <20150429014723.7a3deda4@gmail.com> References: <20150429014723.7a3deda4@gmail.com> Message-ID: I'm in favor of this move. But a question for you: what's the use case for which you're using monad-peel? Most of the cases I've had (and I've seen others have) now use monad-control instead. On Wed, Apr 29, 2015 at 2:13 AM Sergey Alirzaev wrote: > I'd like to take the maintenance of monad-peel as it's currently broken > and Anders seems unavailable. > > -- > () ascii ribbon campaign - against html mail > /\ http://arc.pasp.de/ - against proprietary attachments > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From erkokl at gmail.com Wed Apr 29 07:21:58 2015 From: erkokl at gmail.com (Levent Erkok) Date: Wed, 29 Apr 2015 00:21:58 -0700 Subject: Proposal: Add "fma" to the RealFloat class Message-ID: This proposal is very much in the spirit of the earlier proposal on adding new float/double functions; for instance see here: https://mail.haskell.org/pipermail/libraries/2014-April/022667.html "fma" (a.k.a. fused-multiply-add) is one of those functions; which is the workhorse in many HPC applications. The idea is to multiply two floats and add a third with just one rounding, and thus preserving more precision. There are a multitude of applications for this operation in engineering data-analysis, and modern processors come with custom implementations and a lot of hardware to support it natively. I created a ticket along these lines already: https://ghc.haskell.org/trac/ghc/ticket/10364 Edward suggested that the matter should further be discussed here. I think the proposal is rather straightforward, and should be noncontroversial. To wit, we shall add a new method to the RealFloat class: class (RealFrac a, Floating a) => RealFloat a where ... fma :: a -> a -> a -> a The intention is that fma x y z = x * y + z except the multiplication and addition are done infinitely-precisely, and then rounded only once; as opposed to two roundings as one would get with the above implementation. Most modern architectures directly support this operation so we can map it easily; and in case the architecture does not have it available, we can get it via the C-math libraries, where it appears under the names fma (the double version), and fmaf (the float version.) There should be no default definitions; as an incorrect (two-rounding version) would essentially beat the purpose of having fma in the first place. While the name "fma" is well-established in the arithmetic/hardware community and in the C-library, we can also go with "fusedMultiplyAdd," if that is deemed more clear. Discussion period: 2 weeks. -------------- next part -------------- An HTML attachment was scrubbed... URL: From roma at ro-che.info Wed Apr 29 07:31:36 2015 From: roma at ro-che.info (Roman Cheplyaka) Date: Wed, 29 Apr 2015 10:31:36 +0300 Subject: Proposal: Add "fma" to the RealFloat class In-Reply-To: References: Message-ID: <554088D8.9070807@ro-che.info> I think there *should* be a default definition in terms of (+) and (*). A person who defines their own instance for their own purpose should be free to ignore this function if it's not needed for their specific application. On 29/04/15 10:21, Levent Erkok wrote: > This proposal is very much in the spirit of the earlier proposal on > adding new float/double functions; for instance see > here: https://mail.haskell.org/pipermail/libraries/2014-April/022667.html > > "fma" (a.k.a. fused-multiply-add) is one of those functions; which is > the workhorse in many HPC applications. The idea is to multiply two > floats and add a third with just one rounding, and thus preserving more > precision. There are a multitude of applications for this operation in > engineering data-analysis, and modern processors come with custom > implementations and a lot of hardware to support it natively. > > I created a ticket along these lines > already: https://ghc.haskell.org/trac/ghc/ticket/10364 > > Edward suggested that the matter should further be discussed here. > > I think the proposal is rather straightforward, and should be > noncontroversial. To wit, we shall add a new method to the RealFloat class: > > class (RealFrac a, Floating a) => RealFloat a where > ... > fma :: a -> a -> a -> a > > The intention is that > > fma x y z = x * y + z > > except the multiplication and addition are done infinitely-precisely, > and then rounded only once; as opposed to two roundings as one would get > with the above implementation. Most modern architectures directly > support this operation so we can map it easily; and in case the > architecture does not have it available, we can get it via the C-math > libraries, where it appears under the names fma (the double version), > and fmaf (the float version.) > > There should be no default definitions; as an incorrect (two-rounding > version) would essentially beat the purpose of having fma in the first > place. > > While the name "fma" is well-established in the arithmetic/hardware > community and in the C-library, we can also go with "fusedMultiplyAdd," > if that is deemed more clear. > > Discussion period: 2 weeks. > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From ivan.miljenovic at gmail.com Wed Apr 29 07:38:50 2015 From: ivan.miljenovic at gmail.com (Ivan Lazar Miljenovic) Date: Wed, 29 Apr 2015 17:38:50 +1000 Subject: Proposal: Add "fma" to the RealFloat class In-Reply-To: References: Message-ID: On 29 April 2015 at 17:21, Levent Erkok wrote: > This proposal is very much in the spirit of the earlier proposal on adding > new float/double functions; for instance see here: > https://mail.haskell.org/pipermail/libraries/2014-April/022667.html > > "fma" (a.k.a. fused-multiply-add) is one of those functions; which is the > workhorse in many HPC applications. The idea is to multiply two floats and > add a third with just one rounding, and thus preserving more precision. > There are a multitude of applications for this operation in engineering > data-analysis, and modern processors come with custom implementations and a > lot of hardware to support it natively. > > I created a ticket along these lines already: > https://ghc.haskell.org/trac/ghc/ticket/10364 > > Edward suggested that the matter should further be discussed here. > > I think the proposal is rather straightforward, and should be > noncontroversial. To wit, we shall add a new method to the RealFloat class: > > class (RealFrac a, Floating a) => RealFloat a where > ... > fma :: a -> a -> a -> a > > The intention is that > > fma x y z = x * y + z Can we please have a better name (even if it's just "fusedMultipleAdd")? I have no real opinion on adding this function or not, but just seeing that function (in other code, doing ":info RealFloat" in ghci, etc.) tells me nothing about what it is. Ideally we wouldn't have to rely upon reading Haddock to understand random TLAs in code. > > except the multiplication and addition are done infinitely-precisely, and > then rounded only once; as opposed to two roundings as one would get with > the above implementation. Most modern architectures directly support this > operation so we can map it easily; and in case the architecture does not > have it available, we can get it via the C-math libraries, where it appears > under the names fma (the double version), and fmaf (the float version.) > > There should be no default definitions; as an incorrect (two-rounding > version) would essentially beat the purpose of having fma in the first > place. > > While the name "fma" is well-established in the arithmetic/hardware > community and in the C-library, we can also go with "fusedMultiplyAdd," if > that is deemed more clear. > > Discussion period: 2 weeks. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -- Ivan Lazar Miljenovic Ivan.Miljenovic at gmail.com http://IvanMiljenovic.wordpress.com From lemming at henning-thielemann.de Wed Apr 29 09:19:37 2015 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Wed, 29 Apr 2015 11:19:37 +0200 (CEST) Subject: Proposal: Add "fma" to the RealFloat class In-Reply-To: References: Message-ID: On Wed, 29 Apr 2015, Levent Erkok wrote: > This proposal is very much in the spirit of the earlier proposal on adding new float/double functions; for > instance see here:?https://mail.haskell.org/pipermail/libraries/2014-April/022667.html Btw. what was the final decision with respect to log1p and expm1? I suggest that the decision for 'fma' will be made consistently with 'log1p' and 'expm1'. > "fma" (a.k.a. fused-multiply-add) is one of those functions; which is the workhorse in many HPC applications. > The idea is to multiply two floats and add a third with just one rounding, and thus preserving more precision. > There are a multitude of applications for this operation in engineering data-analysis, and modern processors > come with custom implementations and a lot of hardware to support it natively. Ok, the proposal is about increasing precision. One could also hope that a single fma operation is faster than separate addition and multiplication but as far as I know, fma can even be slower since it has more data dependencies. > I think the proposal is rather straightforward, and should be noncontroversial. To wit, we shall add a new > method to the RealFloat class: > > ? class (RealFrac a, Floating a) => RealFloat a where > ? ? ? ... > ? ? ? fma :: a -> a -> a -> a RealFloat excludes Complex. > There should be no default definitions; as an incorrect (two-rounding > version) would essentially beat the purpose of having fma in the first > place. I just read again the whole expm1 thread and default implementations with possible loss of precision seem to be the best option. This way, one can mechanically replace all occurrences of (x*y+z) by (fma x y z) and will not make anything worse. Types with a guaranteed high precision should be put in a Fused class. > While the name "fma" is well-established in the arithmetic/hardware > community and in the C-library, we can also go with "fusedMultiplyAdd," > if that is deemed more clear. Although I like descriptive names, the numeric classes already contain mostly abbreviations (abs, exp, sin, tanh, ...) Thus I would prefer the abbreviation for consistency. Btw. in DSP 56002 the same operation is called MAC (multiply-accumulate). From voldermort at hotmail.com Wed Apr 29 11:24:37 2015 From: voldermort at hotmail.com (Jeremy) Date: Wed, 29 Apr 2015 04:24:37 -0700 (MST) Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: <552916D4.9070206@plaimi.net> References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> Message-ID: <1430306677298-5808129.post@n5.nabble.com> So what's the conclusion on this? We seem to have a strong consensus on going ahead with the proposal, and a weaker consensus for doing so via the long path. -- View this message in context: http://haskell.1045720.n5.nabble.com/Proposal-Make-Semigroup-as-a-superclass-of-Monoid-tp5767835p5808129.html Sent from the Haskell - Libraries mailing list archive at Nabble.com. From stephen.tetley at gmail.com Wed Apr 29 12:51:02 2015 From: stephen.tetley at gmail.com (Stephen Tetley) Date: Wed, 29 Apr 2015 13:51:02 +0100 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: <1430306677298-5808129.post@n5.nabble.com> References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: The consensus seems largely to favour the high level proposal to add a Semigroup class, but there hasn't been much discussion of the implementation details i.e. what to do about mappend or a Semigroup-like candidate (problematic for empty lists, of course). On 29 April 2015 at 12:24, Jeremy wrote: > So what's the conclusion on this? We seem to have a strong consensus on going > ahead with the proposal, and a weaker consensus for doing so via the long > path. > > > > -- > View this message in context: http://haskell.1045720.n5.nabble.com/Proposal-Make-Semigroup-as-a-superclass-of-Monoid-tp5767835p5808129.html > Sent from the Haskell - Libraries mailing list archive at Nabble.com. > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries From david.feuer at gmail.com Wed Apr 29 13:13:26 2015 From: david.feuer at gmail.com (David Feuer) Date: Wed, 29 Apr 2015 09:13:26 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: What's problematic about empty lists for semigroups? On Wed, Apr 29, 2015 at 8:51 AM, Stephen Tetley wrote: > The consensus seems largely to favour the high level proposal to add a > Semigroup class, but there hasn't been much discussion of the > implementation details i.e. what to do about mappend or a > Semigroup-like candidate (problematic for empty lists, of course). > > > > On 29 April 2015 at 12:24, Jeremy wrote: > > So what's the conclusion on this? We seem to have a strong consensus on > going > > ahead with the proposal, and a weaker consensus for doing so via the long > > path. > > > > > > > > -- > > View this message in context: > http://haskell.1045720.n5.nabble.com/Proposal-Make-Semigroup-as-a-superclass-of-Monoid-tp5767835p5808129.html > > Sent from the Haskell - Libraries mailing list archive at Nabble.com. > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephen.tetley at gmail.com Wed Apr 29 13:51:14 2015 From: stephen.tetley at gmail.com (Stephen Tetley) Date: Wed, 29 Apr 2015 14:51:14 +0100 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: Empty lists are problematic if you want a mconcat like operation. Edward Kmett's semigroups package introduces an EmptyList type to avoid this (the downside being it introduces an EmptyList type). If you don't want an mconcat like operation then Semigroup only has one useful operation (<>). On 29 April 2015 at 14:13, David Feuer wrote: > What's problematic about empty lists for semigroups? > > On Wed, Apr 29, 2015 at 8:51 AM, Stephen Tetley > wrote: >> >> The consensus seems largely to favour the high level proposal to add a >> Semigroup class, but there hasn't been much discussion of the >> implementation details i.e. what to do about mappend or a >> Semigroup-like candidate (problematic for empty lists, of course). >> >> >> >> On 29 April 2015 at 12:24, Jeremy wrote: >> > So what's the conclusion on this? We seem to have a strong consensus on >> > going >> > ahead with the proposal, and a weaker consensus for doing so via the >> > long >> > path. >> > >> > >> > >> > -- >> > View this message in context: >> > http://haskell.1045720.n5.nabble.com/Proposal-Make-Semigroup-as-a-superclass-of-Monoid-tp5767835p5808129.html >> > Sent from the Haskell - Libraries mailing list archive at Nabble.com. >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > From david.feuer at gmail.com Wed Apr 29 13:57:43 2015 From: david.feuer at gmail.com (David Feuer) Date: Wed, 29 Apr 2015 09:57:43 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: Kmett's NonEmpty type (or similar) is the solution to this, but really, why do you need an mconcat-like operation? On Wed, Apr 29, 2015 at 9:51 AM, Stephen Tetley wrote: > Empty lists are problematic if you want a mconcat like operation. > > Edward Kmett's semigroups package introduces an EmptyList type to > avoid this (the downside being it introduces an EmptyList type). > > If you don't want an mconcat like operation then Semigroup only has > one useful operation (<>). > > > > On 29 April 2015 at 14:13, David Feuer wrote: > > What's problematic about empty lists for semigroups? > > > > On Wed, Apr 29, 2015 at 8:51 AM, Stephen Tetley < > stephen.tetley at gmail.com> > > wrote: > >> > >> The consensus seems largely to favour the high level proposal to add a > >> Semigroup class, but there hasn't been much discussion of the > >> implementation details i.e. what to do about mappend or a > >> Semigroup-like candidate (problematic for empty lists, of course). > >> > >> > >> > >> On 29 April 2015 at 12:24, Jeremy wrote: > >> > So what's the conclusion on this? We seem to have a strong consensus > on > >> > going > >> > ahead with the proposal, and a weaker consensus for doing so via the > >> > long > >> > path. > >> > > >> > > >> > > >> > -- > >> > View this message in context: > >> > > http://haskell.1045720.n5.nabble.com/Proposal-Make-Semigroup-as-a-superclass-of-Monoid-tp5767835p5808129.html > >> > Sent from the Haskell - Libraries mailing list archive at Nabble.com. > >> > _______________________________________________ > >> > Libraries mailing list > >> > Libraries at haskell.org > >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > >> _______________________________________________ > >> Libraries mailing list > >> Libraries at haskell.org > >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephen.tetley at gmail.com Wed Apr 29 13:52:50 2015 From: stephen.tetley at gmail.com (Stephen Tetley) Date: Wed, 29 Apr 2015 14:52:50 +0100 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: Cough - I meant semigroups introduces a NonEmpty list type. On 29 April 2015 at 14:51, Stephen Tetley wrote: > Empty lists are problematic if you want a mconcat like operation. > > Edward Kmett's semigroups package introduces an EmptyList type to > avoid this (the downside being it introduces an EmptyList type). > > If you don't want an mconcat like operation then Semigroup only has > one useful operation (<>). > > > > On 29 April 2015 at 14:13, David Feuer wrote: >> What's problematic about empty lists for semigroups? >> From stephen.tetley at gmail.com Wed Apr 29 14:14:50 2015 From: stephen.tetley at gmail.com (Stephen Tetley) Date: Wed, 29 Apr 2015 15:14:50 +0100 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: > why do you need an mconcat-like operation? Well, the more operations the better, especially derived ones rather than ones baked into the class. For me a class with only one operation wouldn't really meet the Fairburn threshold. In this case, I'd abstain from voting against as the consensus is high but I would like to see a proper proposal for what adding Semigroup includes (and what it leaves out) rather than a straw in the wind notion to just add it. On 29 April 2015 at 14:57, David Feuer wrote: > Kmett's NonEmpty type (or similar) is the solution to this, but really, why > do you need an mconcat-like operation? > > On Wed, Apr 29, 2015 at 9:51 AM, Stephen Tetley > wrote: >> >> Empty lists are problematic if you want a mconcat like operation. >> >> Edward Kmett's semigroups package introduces an EmptyList type to >> avoid this (the downside being it introduces an EmptyList type). >> >> If you don't want an mconcat like operation then Semigroup only has >> one useful operation (<>). >> >> >> >> On 29 April 2015 at 14:13, David Feuer wrote: >> > What's problematic about empty lists for semigroups? >> > >> > On Wed, Apr 29, 2015 at 8:51 AM, Stephen Tetley >> > >> > wrote: >> >> >> >> The consensus seems largely to favour the high level proposal to add a >> >> Semigroup class, but there hasn't been much discussion of the >> >> implementation details i.e. what to do about mappend or a >> >> Semigroup-like candidate (problematic for empty lists, of course). >> >> >> >> >> >> >> >> On 29 April 2015 at 12:24, Jeremy wrote: >> >> > So what's the conclusion on this? We seem to have a strong consensus >> >> > on >> >> > going >> >> > ahead with the proposal, and a weaker consensus for doing so via the >> >> > long >> >> > path. >> >> > >> >> > >> >> > >> >> > -- >> >> > View this message in context: >> >> > >> >> > http://haskell.1045720.n5.nabble.com/Proposal-Make-Semigroup-as-a-superclass-of-Monoid-tp5767835p5808129.html >> >> > Sent from the Haskell - Libraries mailing list archive at Nabble.com. >> >> > _______________________________________________ >> >> > Libraries mailing list >> >> > Libraries at haskell.org >> >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> _______________________________________________ >> >> Libraries mailing list >> >> Libraries at haskell.org >> >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > >> > > > From spam at scientician.net Wed Apr 29 14:28:53 2015 From: spam at scientician.net (Bardur Arantsson) Date: Wed, 29 Apr 2015 16:28:53 +0200 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: <1430306677298-5808129.post@n5.nabble.com> References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: On 29-04-2015 13:24, Jeremy wrote: > So what's the conclusion on this? We seem to have a strong consensus on going > ahead with the proposal, and a weaker consensus for doing so via the long > path. > > Maybe you should work out the details wrt. the concerns/things raised in the thread and do a wiki page detailing all of this? Ideally with some code to review, perhaps? In particular, if you could do a survey of Hackage to find out how many (and which) packages would be affected by this, you would earn a lot of bonus points for due dilligence! :) (I'm definitely +1 on the concept, but it's hard to judge how practical it is without estimates of breakage, etc.) Regards, From asr at eafit.edu.co Wed Apr 29 14:42:03 2015 From: asr at eafit.edu.co (=?UTF-8?B?QW5kcsOpcyBTaWNhcmQtUmFtw61yZXo=?=) Date: Wed, 29 Apr 2015 09:42:03 -0500 Subject: Agda 2.4.2.2. and cpphs 1.19 Message-ID: Hi, The current version of Agda (2.4.2.2) in Hackage doesn't install with the current version of cpphs (1.19) in Hackage due to the following restriction: build-tools: cpphs >= 1.18.6 && < 1.19 Although I'm a maintainer of Agda, using the Hackage web interface I couldn't increase the upper bound for cpphs to 1.20 because this upper bound is inside a cabal flag. Since this problem has been repeatedly reported by Agda's users, could some Hackage trustee fix the problem, please. Thanks, -- Andr?s From david.feuer at gmail.com Wed Apr 29 14:48:57 2015 From: david.feuer at gmail.com (David Feuer) Date: Wed, 29 Apr 2015 10:48:57 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: I'd definitely be -1 on an mconcat-like operation for Semigroup. I think mconcat mostly fails to be useful for monoid, because all it has over fold is knowledge of right and left bias and the theoretical (but practically, I think, rather hard to exploit) ability to group and locally rearrange elements while summing. Kmett has a version of Foldable designed to use with semigroups, and I'd be okay with adding that. On Wed, Apr 29, 2015 at 10:14 AM, Stephen Tetley wrote: > > why do you need an mconcat-like operation? > > Well, the more operations the better, especially derived ones rather > than ones baked into the class. > > For me a class with only one operation wouldn't really meet the > Fairburn threshold. In this case, I'd abstain from voting against as > the consensus is high but I would like to see a proper proposal for > what adding Semigroup includes (and what it leaves out) rather than a > straw in the wind notion to just add it. > > > On 29 April 2015 at 14:57, David Feuer wrote: > > Kmett's NonEmpty type (or similar) is the solution to this, but really, > why > > do you need an mconcat-like operation? > > > > On Wed, Apr 29, 2015 at 9:51 AM, Stephen Tetley < > stephen.tetley at gmail.com> > > wrote: > >> > >> Empty lists are problematic if you want a mconcat like operation. > >> > >> Edward Kmett's semigroups package introduces an EmptyList type to > >> avoid this (the downside being it introduces an EmptyList type). > >> > >> If you don't want an mconcat like operation then Semigroup only has > >> one useful operation (<>). > >> > >> > >> > >> On 29 April 2015 at 14:13, David Feuer wrote: > >> > What's problematic about empty lists for semigroups? > >> > > >> > On Wed, Apr 29, 2015 at 8:51 AM, Stephen Tetley > >> > > >> > wrote: > >> >> > >> >> The consensus seems largely to favour the high level proposal to add > a > >> >> Semigroup class, but there hasn't been much discussion of the > >> >> implementation details i.e. what to do about mappend or a > >> >> Semigroup-like candidate (problematic for empty lists, of course). > >> >> > >> >> > >> >> > >> >> On 29 April 2015 at 12:24, Jeremy wrote: > >> >> > So what's the conclusion on this? We seem to have a strong > consensus > >> >> > on > >> >> > going > >> >> > ahead with the proposal, and a weaker consensus for doing so via > the > >> >> > long > >> >> > path. > >> >> > > >> >> > > >> >> > > >> >> > -- > >> >> > View this message in context: > >> >> > > >> >> > > http://haskell.1045720.n5.nabble.com/Proposal-Make-Semigroup-as-a-superclass-of-Monoid-tp5767835p5808129.html > >> >> > Sent from the Haskell - Libraries mailing list archive at > Nabble.com. > >> >> > _______________________________________________ > >> >> > Libraries mailing list > >> >> > Libraries at haskell.org > >> >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > >> >> _______________________________________________ > >> >> Libraries mailing list > >> >> Libraries at haskell.org > >> >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > >> > > >> > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From hesselink at gmail.com Wed Apr 29 14:51:54 2015 From: hesselink at gmail.com (Erik Hesselink) Date: Wed, 29 Apr 2015 16:51:54 +0200 Subject: Agda 2.4.2.2. and cpphs 1.19 In-Reply-To: References: Message-ID: I don't think it's currently possible to edit the build-tools field through the web interface for anyone (doesn't matter if it's inside a flag). It seems the simplest solution is to just release a new version with a relaxed constraint. Regards, Erik On Wed, Apr 29, 2015 at 4:42 PM, Andr?s Sicard-Ram?rez wrote: > Hi, > > The current version of Agda (2.4.2.2) in Hackage doesn't install with > the current version of cpphs (1.19) in Hackage due to the following > restriction: > > build-tools: cpphs >= 1.18.6 && < 1.19 > > Although I'm a maintainer of Agda, using the Hackage web interface I > couldn't increase the upper bound for cpphs to 1.20 because this upper > bound is inside a cabal flag. > > Since this problem has been repeatedly reported by Agda's users, could > some Hackage trustee fix the problem, please. > > Thanks, > > -- > Andr?s > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries From asr at eafit.edu.co Wed Apr 29 15:34:52 2015 From: asr at eafit.edu.co (=?UTF-8?B?QW5kcsOpcyBTaWNhcmQtUmFtw61yZXo=?=) Date: Wed, 29 Apr 2015 10:34:52 -0500 Subject: Agda 2.4.2.2. and cpphs 1.19 In-Reply-To: References: Message-ID: On 29 April 2015 at 09:51, Erik Hesselink wrote: > I don't think it's currently possible to edit the build-tools field > through the web interface for anyone (doesn't matter if it's inside a > flag). Thanks for the information. > It seems the simplest solution is to just release a new version > with a relaxed constraint. Since that the --allow-newer doesn't work with build-tools, I've been suggesting to use the --with-cpphs flag with a supported version of cpphs. Best, -- Andr?s From ekmett at gmail.com Wed Apr 29 15:39:15 2015 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 29 Apr 2015 11:39:15 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: Well, it seems the consensus is high enough that we'll try to go ahead with this. As it affects the Prelude, we may put out another poll / wider broadcast just to avoid any appearance of ambushing folks with another change to the Prelude without announcement, but I think at this point my intent is to pick a path to make this happen. -Edward On Wed, Apr 29, 2015 at 8:51 AM, Stephen Tetley wrote: > The consensus seems largely to favour the high level proposal to add a > Semigroup class, but there hasn't been much discussion of the > implementation details i.e. what to do about mappend or a > Semigroup-like candidate (problematic for empty lists, of course). > > > > On 29 April 2015 at 12:24, Jeremy wrote: > > So what's the conclusion on this? We seem to have a strong consensus on > going > > ahead with the proposal, and a weaker consensus for doing so via the long > > path. > > > > > > > > -- > > View this message in context: > http://haskell.1045720.n5.nabble.com/Proposal-Make-Semigroup-as-a-superclass-of-Monoid-tp5767835p5808129.html > > Sent from the Haskell - Libraries mailing list archive at Nabble.com. > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Wed Apr 29 15:48:52 2015 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 29 Apr 2015 11:48:52 -0400 Subject: Proposal: Add "fma" to the RealFloat class In-Reply-To: References: Message-ID: On Wed, Apr 29, 2015 at 5:19 AM, Henning Thielemann < lemming at henning-thielemann.de> wrote: > > On Wed, 29 Apr 2015, Levent Erkok wrote: > > This proposal is very much in the spirit of the earlier proposal on >> adding new float/double functions; for >> instance see here: >> https://mail.haskell.org/pipermail/libraries/2014-April/022667.html >> > > Btw. what was the final decision with respect to log1p and expm1? > > I suggest that the decision for 'fma' will be made consistently with > 'log1p' and 'expm1'. We decided to add them. Then we didn't do it in 7.10. I'll talk to Herbert about how to proceed to get them in 7.12, though we may wait until we know the outcome of this proposal and fuse the two together into one patch. > I think the proposal is rather straightforward, and should be >> noncontroversial. To wit, we shall add a new >> method to the RealFloat class: >> >> class (RealFrac a, Floating a) => RealFloat a where >> ... >> fma :: a -> a -> a -> a >> > > > RealFloat excludes Complex. Good point. If we wanted to we could push this all the way up to Num given the operations involved, and I could see that you could benefit from it there for types that have nothing to do with floating point, e.g. modular arithmetic could get away with using a single 'mod'. There should be no default definitions; as an incorrect (two-rounding >> version) would essentially beat the purpose of having fma in the first >> place. >> > > I just read again the whole expm1 thread and default implementations with > possible loss of precision seem to be the best option. This way, one can > mechanically replace all occurrences of (x*y+z) by (fma x y z) and will not > make anything worse. Types with a guaranteed high precision should be put > in a Fused class. I argued rather strenuously for this for the expm1, log1p case, but wasn't able to win folks over. While the name "fma" is well-established in the arithmetic/hardware >> community and in the C-library, we can also go with "fusedMultiplyAdd," if >> that is deemed more clear. >> > > Although I like descriptive names, the numeric classes already contain > mostly abbreviations (abs, exp, sin, tanh, ...) Thus I would prefer the > abbreviation for consistency. Btw. in DSP 56002 the same operation is > called MAC (multiply-accumulate). > I have no strong preference on the name. fusedMultiplyAdd has the benefit that a non-domain-expert can figure it out. fma is traditional. -Edward -------------- next part -------------- An HTML attachment was scrubbed... URL: From malcolm.wallace at me.com Wed Apr 29 18:28:02 2015 From: malcolm.wallace at me.com (Malcolm Wallace) Date: Wed, 29 Apr 2015 19:28:02 +0100 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: On 29 Apr 2015, at 16:39, Edward Kmett wrote: > Well, it seems the consensus is high enough that we'll try to go ahead with this. As it affects the Prelude, we may put out another poll / wider broadcast just to avoid any appearance of ambushing folks with another change to the Prelude without announcement, but I think at this point my intent is to pick a path to make this happen. Whilst the change itself might have merit, I have to say I'm getting really fed up of all these tiny and piecemeal change proposals for the Prelude. I'd be much more in favour of something radical, like removing 80% of the Prelude altogether, and forcing people to import list operations from Data.List, monad stuff from Control.Monad, number hierarchies from Data.Numeric, etc. Then we would not have to suffer all of these long-drawn-out and painful yet minor breakages in future. With a minimal Prelude, all of the recent proposed changes, from Applicative/Monad, to Foldable/Traversable, to Semigroup/Monoid, could have been achieved purely via libraries, and if someone doesn't like a change, they can just pick a different library. Regards, Malcolm From ekmett at gmail.com Wed Apr 29 19:19:29 2015 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 29 Apr 2015 15:19:29 -0400 Subject: Proposal: Make Semigroup as a superclass of Monoid In-Reply-To: References: <1427631633145-5767835.post@n5.nabble.com> <552916D4.9070206@plaimi.net> <1430306677298-5808129.post@n5.nabble.com> Message-ID: On Wed, Apr 29, 2015 at 2:28 PM, Malcolm Wallace wrote: > > Whilst the change itself might have merit, I have to say I'm getting > really fed up of all these tiny and piecemeal change proposals for the > Prelude. I'd be much more in favour of something radical, like removing > 80% of the Prelude altogether, and forcing people to import list operations > from Data.List, monad stuff from Control.Monad, number hierarchies from > Data.Numeric, etc. Then we would not have to suffer all of these > long-drawn-out and painful yet minor breakages in future. With a minimal > Prelude, all of the recent proposed changes, from Applicative/Monad, to > Foldable/Traversable, to Semigroup/Monoid, could have been achieved purely > via libraries, and if someone doesn't like a change, they can just pick a > different library. > ... and if they are exiled all the way into separate libraries then nobodies code works together, because nobody wants to incur a dependency they don't need at the moment. For example, stuff in the containers package implement the classes in base, but I'd wager pretty heavily that I'd have a hard time convincing Johan or Milan to pick up _any_ dependency they absolutely didn't have to have to make that library go. As messy and organic as it is having a shared base to build on it gives us a common names and instances for things we all have in common. It may have been better to start with the culture you suggest. It would have reduced this particular pain point, but the knock-on consequences of such a design are pretty terrible. So we're left with the choice of nickel and diming you with small changes that you can work around with nice warning periods as you get hit by them or making bigger changes that require harder actions. =/ -Edward -------------- next part -------------- An HTML attachment was scrubbed... URL: From kenta at mit.edu Wed Apr 29 22:19:25 2015 From: kenta at mit.edu (Ken T Takusagawa) Date: Wed, 29 Apr 2015 18:19:25 -0400 (EDT) Subject: Proposal: Add "fma" to the RealFloat class In-Reply-To: References: Message-ID: On Wed, 29 Apr 2015, Edward Kmett wrote: > Good point. If we wanted to we could push this all the way up to Num given the operations > involved, and I could see that you could benefit from it there for types that have nothing > to do with floating point, e.g. modular arithmetic could get away with using a single 'mod'. I too advocate this go in Num. The place I anticipate seeing fma being used is in some polymorphic linear algebra library, and it is not uncommon (having recently done this myself) to do linear algebra on things that aren't RealFloat, e.g., Rational, Complex, or number-theoretic fields. --ken From winterkoninkje at gmail.com Thu Apr 30 17:56:21 2015 From: winterkoninkje at gmail.com (wren romano) Date: Thu, 30 Apr 2015 13:56:21 -0400 Subject: Proposal: Add "fma" to the RealFloat class In-Reply-To: References: Message-ID: On Wed, Apr 29, 2015 at 11:48 AM, Edward Kmett wrote: > Good point. If we wanted to we could push this all the way up to Num given > the operations involved, and I could see that you could benefit from it > there for types that have nothing to do with floating point, e.g. modular > arithmetic could get away with using a single 'mod'. I'm strongly in favor of adding fma *somewhere*, even if just as a family of primops; though, of course, it'd be nicer to put it in a type class so we don't have to pull in GHC.Exts. And as far as type classes go, I'm strongly in favor of pushing it all the way up to Num (or rather, to Semiring if only we had such a thing). There's no conceptual reason for it to live in RealFloat. -- Live well, ~wren From d at davidterei.com Thu Apr 30 22:58:23 2015 From: d at davidterei.com (David Terei) Date: Thu, 30 Apr 2015 15:58:23 -0700 Subject: Roles, GND, Data.Coerce Message-ID: All, An issue that came up with GHC 7.8 was the design of Roles and Data.Coerce, with it's ability to break module abstractions by default, requiring programmers adopt explicit role annotations to enforce some types of invariants for abstract data types. Because of this issue, as of now, GND & Data.Coerce are still disabled in Safe Haskell. We'd like to change this but need feedback from everyone. I've written up a wiki page with lots of information on the issue: https://ghc.haskell.org/trac/ghc/wiki/SafeRoles Please read, it has information on how Roles work, the problem it raises and subtleties in the current system. Possible paths forward are also there, but I'll include below. Please be aware that this discussion is about Roles in general, not specifically how when using -XSafe. Ideally we'd come up with a solution that works regardless of if using Safe Haskell or not. I personally like option (3), although it isn't clear to me how hairy the implementation would be. == Possible Paths Forward for Roles == 1) Do Nothing -- Keep Roles & GND unchanged, keep them unsafe in Safe Haskell. 2) Accept as Safe -- Keep Roles & GND unchanged, accept them as safe in Safe Haskell and warn users that they neednominal role annotations on ADTs. 3) In-scope constructor restriction for lifting instances -- The newtype constructor restriction for unwrapping instances could be extended to both data types, and the lifting instances of Data.Coerce. This is, GND & Coercing under a type constructor is allowed if (a) all involved constructors are in scope, or (b) the constructors involved have been explicitly declared to allow coercion without them being in scope. I.e., (b) allows library authors to opt-into the current GHC behavior. This would require new syntax, probably just an explicit deriving Coercible statement. 4) Change default role to nominal -- This will prioritize safety over GND, and the belief is that it may break a lot of code. Worse, that it will be an ongoing tax as role annotations will be needed to enable GND. 5) Nominal default when constructors aren't exported -- When a module doesn't export all the constructors of a data type, then the type parameters of the data type should default to nominal. This heuristic seems to capture somewhat the intention of the user, but given the practice of defining an Internal module that exports everything, it seems of limited use. 6) Nominal default in future -- Add a new extension, SafeNewtypeDeriving that switches the default role to nominal, but continue to provide a deprecated GND extension to help with the transition. The claims in support of representational roles as default though believe that nominal by default has an ongoing, continuous tax, not just a transition cost. So it isn't clear that any scheme like this satisfies that argument. 7) Safe Haskell Specific -- Many of the above approaches could be adopted in a Safe Haskell specific manner. This isn't ideal as it makes safe-inference harder and Safe Haskell less likely to remain viable going forward. Richard suggests one such idea. == The belief by many people seems to be that (4) and (6) would be too much of burden. I'd like to avoid (7) if possible. It isn't clear to me if (7) ends up better than (2). I'm going to try to setup some infastructure for compiling Hackage so that we can measure how impactful these changes would be. Cheers, David