From mail at joachim-breitner.de Wed Oct 1 12:59:39 2014 From: mail at joachim-breitner.de (Joachim Breitner) Date: Wed, 01 Oct 2014 14:59:39 +0200 Subject: Proposal: (breaking change to avoid fragile breakage) change the definition of foldr2, zip, and zipWith In-Reply-To: <1410164685.2670.3.camel@joachim-breitner.de> References: <1410164685.2670.3.camel@joachim-breitner.de> Message-ID: <1412168379.2665.9.camel@joachim-breitner.de> Hi, Am Montag, den 08.09.2014, 10:24 +0200 schrieb Joachim Breitner: > Given that nobody complained about the standard-non-conformance so far I > think having a symmetric zip where the RULES are semantics-preserving is > more useful than strictly following the report. But I could be convinced > otherwise. > > > David, I think you can go ahead and prepare a patch. People can still > speak up before (and even after) it is applied if they disagree. nobody complained, so I?m going to apply David?s patch at https://ghc.haskell.org/trac/ghc/attachment/ticket/9495/foldr2.diff now. 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 marlowsd at gmail.com Thu Oct 2 20:25:27 2014 From: marlowsd at gmail.com (Simon Marlow) Date: Thu, 02 Oct 2014 21:25:27 +0100 Subject: Proposal: Use uninterruptibleMask for cleanup actions in Control.Exception In-Reply-To: References: <20140904144629.GA21972@sniper> <5409D931.1030503@gmail.com> <5422BE62.7010205@gmail.com> Message-ID: <542DB4B7.8010102@gmail.com> On 24/09/2014 17:58, Merijn Verstraaten wrote: > Well, another issue that was raised (I forget by whom!) was the fact > that stackoverflows are currently thrown externally from the > executing thread and that this should really be changed into being > thrown to the thread by itself, thereby avoiding the mask. Yeah, a stack overflow is an asynchronous exception. Tt is not thrown by any particular thread, but it is treated as an async exception from the point of view of the receiving thread. And this is the right thing to do, since a stack overflow can occur absolutely anywhere, so it has exactly the characteristics of an async exception. So it is already the case that a stack overflow inside mask does not cause an exception. Instead the exception is deferred until the thread exits the mask. This proposal wouldn't change anything in that respect. Cheers, Simon > > Cheers, Merijn > > On 24 Sep 2014, at 05:51 , Simon Marlow wrote: >> Ok, sorry for the delay, we still need a resolution on this one. >> >> So thanks to your persuasive comments I think I'm convinced. What >> finally tipped me over the edge was this: >> >> https://phabricator.haskell.org/diffusion/GHC/browse/master/libraries/base/Control/Concurrent/QSem.hs;165072b334ebb2ccbef38a963ac4d126f1e08c96$103-112 >> >> >> >> It turns out I've been a victim of this "bug" myself :-) So let's fix it. >> >> But what is the cost? Adding an uninterruptibleMask won't be free. >> >> In the case of `catch`, since the mask is already built in to the >> primitive, we can just change it to be an uninterruptibleMask, and >> that applies to handle and onException too. For `finally` we can >> replace the mask with an uninterruptibleMask, but for `bracket` we >> have to add a new layer of uninterruptibleMask. >> >> Lots of documentation probably needs to be updated. Any chance >> you could make a patch and upload it to Phabricator? >> >> Cheers, Simon >> >> On 05/09/2014 18:34, Eyal Lotem wrote: >>> Hey Simon, thanks for the reply! >>> >>> >>> On Fri, Sep 5, 2014 at 6:39 PM, Simon Marlow >> > wrote: >>> >>> Eyal, thanks for bringing up this issue. It's been at the back >>> of my mind for a while, but I've never really thought through the >>> issues and consequences of changes. So this is a good >>> opportunity to do that. You point out (in another email in the >>> thread) that: >>> >>> A) Cases that were not interruptible will remain the same. B) >>> Cases that were interruptible were bugs and will be fixed. >>> >>> However, >>> >>> C) Some bugs will turn into deadlocks (unkillable threads) >>> >>> Being able to recover from bugs is an important property in large >>> long-running systems. So this is a serious problem. Hence why I >>> always treat uninterruptibleMask with the deepest suspicion. >>> >>> >>> Recovering from various kinds of failures makes a lot of sense. >>> But how can you recover from arbitrary invariants of the program >>> being broken? >>> >>> For example, if you use a bracket on some semaphore monitoring a >>> global resource. How do you recover from a bug of leaking >>> semaphore tokens? >>> >>> Recovering from crashes of whole processes whose internal state >>> can be recovered to a fresh, usable state, is a great feature. >>> Recovering from thread crashes that share arbitrary mutable >>> state with other threads is not practical, I believe. >>> >>> Let's consider the case where we have an interruptible operation >>> in the handler, and divide it into two (er three): >>> >>> 1. it blocks for a short bounded amount of time. 2. It blocks >>> for a long time 3. It blocks indefinitely >>> >>> These are all buggy, but in different ways. Only (1) is fixed by >>> adding uninterruptibleMask. (2) is "fixed", but in exchange for >>> an unresponsive thread - also undesirable. (3) was a bug in the >>> application code, and turns into a deadlock with >>> uninterruptibleMask, which is undesirable. >>> >>> >>> I think that (1) is by far the most common and is very >>> prevalent. I think 0-time interruptible (that can block but >>> almost never do) operations are the most common cleanup >>> handlers. >>> >>> For (2) and (3), we need to choose the lesser evil: >>> >>> A) Deadlocks and/or unresponsiveness B) Arbitrary invariants >>> being broken and leaks >>> >>> In my experience, A tends to manifest exactly where the bug is, >>> and is therefore easy to debug and mostly a "performance bug" . >>> B tends to manifest as difficult to explain behavior elsewhere >>> from where the bug actually is, and is usually a "correctness >>> bug", which is almost always worse. >>> >>> Therefore, I think A is a far far lesser evil than B, when (2) >>> and (3) are involved. >>> >>> I'd like to reemphasize that this change will almost always fix >>> the problem completely since the most common case is (1), and in >>> rare cases, it will convert B to A, which is also, IMO, very >>> desirable. >>> >>> >>> This is as far as I've got thinking through the issues so far. I >>> wonder to what extent the programmer can and should mitigate >>> these cases, and how much we can help them. I don't want >>> unkillable threads, even when caused by buggy code. >>> >>> >>> Cheers, Simon >>> >>> >>> On 04/09/2014 16:46, Roman Cheplyaka wrote: >>> >>> I find your arguments quite convincing. Count that as +1 from >>> me. >>> >>> Roman >>> >>> >>> >>> _________________________________________________ Libraries >>> mailing list Libraries at haskell.org >>> http://www.haskell.org/__mailman/listinfo/libraries >>> >>> >>> >>> >>> >>> -- Eyal >> _______________________________________________ Libraries mailing >> list Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries > From alexander at plaimi.net Fri Oct 3 09:45:38 2014 From: alexander at plaimi.net (Alexander Berntsen) Date: Fri, 03 Oct 2014 11:45:38 +0200 Subject: Removing MonadFail from Monad In-Reply-To: 52AF7E1F.4000606@gmail.com Message-ID: <542E7042.9010908@plaimi.net> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Seems like a fitting time to breathe fresh air into the lungs of the FRP proposal. :-] +1 for the idea (removing MonadFail) & the proposed solution (reintroducing the MonadFail typeclass). > - Rename `fail`? It's quite a generic name that would be nice to > have in APIs. `failM`? `mfail`? +1 for failM. - -- Alexander alexander at plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iF4EAREIAAYFAlQucEIACgkQRtClrXBQc7X+MQD/VDCV/5rFflWVCnrtxbK/JIuz yvRMEeu6S4R7j3aQyiUA/2MJ8m9ZFXmsxgwX/rAj4MUDOEiQwSNm4Fj2R+zG218t =WUUY -----END PGP SIGNATURE----- From hvr at gnu.org Fri Oct 3 10:12:09 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Fri, 03 Oct 2014 12:12:09 +0200 Subject: Removing MonadFail from Monad In-Reply-To: <52AF7E1F.4000606@gmail.com> (David Luposchainsky's message of "Mon, 16 Dec 2013 23:26:39 +0100") References: <52AF7E1F.4000606@gmail.com> Message-ID: <87vbo1h37q.fsf@gnu.org> On 2013-12-16 at 23:26:39 +0100, David Luposchainsky wrote: [...] > The proposal text can be found at the end of this text (for the mailman > archives), or in pretty HTML here: > https://github.com/quchen/articles/blob/master/monad_fail.md For the record (as I missed this thread back in 2013), I'd be enthusiastically +1 on this Fail-Removal-Proposal :-) From iavor.diatchki at gmail.com Fri Oct 3 18:37:42 2014 From: iavor.diatchki at gmail.com (Iavor Diatchki) Date: Fri, 3 Oct 2014 11:37:42 -0700 Subject: ANN: New version of graphmod (1.2.4) Message-ID: Hello, I am pleased to announce a new version of `graphmod`---a program that helps you visualize the import dependencies between the modules in your Haskell programs. The new feature in version 1.2.4 is support for pruning the dependency graph, which is enabled with the flag -p or --prune-edges. When this option is selected, `graphmod` will ignore imports to modules that are already imported by some of the dependencies of the module. For example, consider the following modules: module A where { import B; import C } module B where { import C } module C where { } When generated with `--prune-edges`, the resulting graph will be: A -> B -> C Note that there is no edge from `A` to `C`, because `C` is already imported by `B`. Happy hacking, -Iavor -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Wed Oct 8 08:15:23 2014 From: david.feuer at gmail.com (David Feuer) Date: Wed, 8 Oct 2014 04:15:23 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf Message-ID: Currently, isSuffixOf is defined like this: xs `isSuffixOf` ys = reverse xs `isPrefixOf` reverse ys If ys is much longer than xs, this is not so wonderful, because we have to reverse the whole spine of ys. It also will fail whenever either xs *or* ys is infinite. The following implementation seems a lot saner (although longer): isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool [] `isSuffixOf` _ = True needle `isSuffixOf` hay = maybe False (\fp -> needle `eq` getEndChunk hay fp) (getFrontPointer needle hay) where eq :: [a] -> [a] -> [a] (x:xs) `eq` (y:ys) = x==y && (xs `eq` ys) getEndChunk :: [a] -> [a] -> [a] getEndChunk (_:hy) (_:fp) = getEndChunk hy fp getEndChunk hy _ = hy getFrontPointer :: [a] -> [a] -> Maybe [a] getFrontPointer [] hy = Just hy getFrontPointer _ [] = Nothing getFrontPointer (_:nd) (_:hy) = getFrontPointer nd hy This doesn't do any of that crazy stuff, and it will work just fine if the needle is infinite. The only slightly sticky point is that it's not *strictly* lazier. In particular, [1,2] `Data.List.isSuffixOf` [undefined, 7] = False [1,2] `isSuffixOf` [undefined, 7] = undefined But note that [1,2] `Data.List.isSuffixOf` [7,undefined] = undefined [1,2] `isSuffixOf` [7, undefined] = False It would be possible to get the same kind of laziness at the end using something structured as above, but it requires some unpleasantness: instead of using needle `eq` getEndChunk hay fp we'd have to use needle `backwardsEq` getEndChunk hay fp (x:xs) `backwardsEq` (y:ys) = (xs `backwardsEq` ys) && x==y This is yucky. My guess is that no one is relying on the current behavior, but I'd like to make sure everyone's okay with this. David -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Wed Oct 8 08:17:35 2014 From: david.feuer at gmail.com (David Feuer) Date: Wed, 8 Oct 2014 04:17:35 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: Message-ID: Sorry, I made a bit of a mistake with eq; it's corrected below. On Wed, Oct 8, 2014 at 4:15 AM, David Feuer wrote: > Currently, isSuffixOf is defined like this: > > xs `isSuffixOf` ys = reverse xs `isPrefixOf` reverse ys > > If ys is much longer than xs, this is not so wonderful, because we have to > reverse the whole spine of ys. It also will fail whenever either xs *or* ys > is infinite. The following implementation seems a lot saner (although > longer): > > isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > needle `isSuffixOf` hay = > maybe False > (\fp -> needle `eq` getEndChunk hay fp) > (getFrontPointer needle hay) > where > eq :: [a] -> [a] -> Bool > (x:xs) `eq` (y:ys) = x==y && (xs `eq` ys) > _ `eq` _ = True > > getEndChunk :: [a] -> [a] -> [a] > getEndChunk (_:hy) (_:fp) = getEndChunk hy fp > getEndChunk hy _ = hy > > getFrontPointer :: [a] -> [a] -> Maybe [a] > getFrontPointer [] hy = Just hy > getFrontPointer _ [] = Nothing > getFrontPointer (_:nd) (_:hy) = getFrontPointer nd hy > > This doesn't do any of that crazy stuff, and it will work just fine if the > needle is infinite. The only slightly sticky point is that it's not > *strictly* lazier. In particular, > > [1,2] `Data.List.isSuffixOf` [undefined, 7] = False > [1,2] `isSuffixOf` [undefined, 7] = undefined > > But note that > > [1,2] `Data.List.isSuffixOf` [7,undefined] = undefined > [1,2] `isSuffixOf` [7, undefined] = False > > It would be possible to get the same kind of laziness at the end using > something structured as above, but it requires some unpleasantness: instead > of using > > needle `eq` getEndChunk hay fp > > we'd have to use > > needle `backwardsEq` getEndChunk hay fp > > (x:xs) `backwardsEq` (y:ys) = (xs `backwardsEq` ys) && x==y > > This is yucky. My guess is that no one is relying on the current behavior, > but I'd like to make sure everyone's okay with this. > > David > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Wed Oct 8 21:50:48 2014 From: david.feuer at gmail.com (David Feuer) Date: Wed, 8 Oct 2014 17:50:48 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: Message-ID: A slight simplification (because I realized the weird thing I was doing won't actually save any time): isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool [] `isSuffixOf` _ = True needle `isSuffixOf` hay = maybe False (\fp -> needle == getEndChunk hay fp) (getFrontPointer needle hay) where getEndChunk :: [a] -> [a] -> [a] getEndChunk (_:hy) (_:fp) = getEndChunk hy fp getEndChunk hy _ = hy getFrontPointer :: [a] -> [a] -> Maybe [a] getFrontPointer [] hy = Just hy getFrontPointer _ [] = Nothing getFrontPointer (_:nd) (_:hy) = getFrontPointer nd hy I still haven't heard from anyone about the slight semantic change. To clarify it slightly, the only aspect that could theoretically be a problem for somebody is that this reverses the order in which the elements of the "needle" are compared to the (length needle) elements at the end of the "haystack". The current implementation compares them from back to front; this one compares them from front to back. That means that if some elements in the needle or near the end of the haystack are undefined, there are cases where this implementation bottoms out when the current one returns False, and vice versa. On Oct 8, 2014 4:17 AM, "David Feuer" wrote: > Sorry, I made a bit of a mistake with eq; it's corrected below. > > On Wed, Oct 8, 2014 at 4:15 AM, David Feuer wrote: > >> Currently, isSuffixOf is defined like this: >> >> xs `isSuffixOf` ys = reverse xs `isPrefixOf` reverse ys >> >> If ys is much longer than xs, this is not so wonderful, because we have >> to reverse the whole spine of ys. It also will fail whenever either xs *or* >> ys is infinite. The following implementation seems a lot saner (although >> longer): >> >> isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool >> [] `isSuffixOf` _ = True >> needle `isSuffixOf` hay = >> maybe False >> (\fp -> needle `eq` getEndChunk hay fp) >> (getFrontPointer needle hay) >> where >> eq :: [a] -> [a] -> Bool >> (x:xs) `eq` (y:ys) = x==y && (xs `eq` ys) >> > _ `eq` _ = True > >> >> getEndChunk :: [a] -> [a] -> [a] >> getEndChunk (_:hy) (_:fp) = getEndChunk hy fp >> getEndChunk hy _ = hy >> >> getFrontPointer :: [a] -> [a] -> Maybe [a] >> getFrontPointer [] hy = Just hy >> getFrontPointer _ [] = Nothing >> getFrontPointer (_:nd) (_:hy) = getFrontPointer nd hy >> >> This doesn't do any of that crazy stuff, and it will work just fine if >> the needle is infinite. The only slightly sticky point is that it's not >> *strictly* lazier. In particular, >> >> [1,2] `Data.List.isSuffixOf` [undefined, 7] = False >> [1,2] `isSuffixOf` [undefined, 7] = undefined >> >> But note that >> >> [1,2] `Data.List.isSuffixOf` [7,undefined] = undefined >> [1,2] `isSuffixOf` [7, undefined] = False >> >> It would be possible to get the same kind of laziness at the end using >> something structured as above, but it requires some unpleasantness: instead >> of using >> >> needle `eq` getEndChunk hay fp >> >> we'd have to use >> >> needle `backwardsEq` getEndChunk hay fp >> >> (x:xs) `backwardsEq` (y:ys) = (xs `backwardsEq` ys) && x==y >> >> This is yucky. My guess is that no one is relying on the current >> behavior, but I'd like to make sure everyone's okay with this. >> >> David >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ndmitchell at gmail.com Thu Oct 9 21:56:48 2014 From: ndmitchell at gmail.com (Neil Mitchell) Date: Thu, 9 Oct 2014 22:56:48 +0100 Subject: [core libraries] List of core libraries In-Reply-To: References: <878ul3ehoc.fsf@gmail.com> Message-ID: I did semi-hand the filepath library over to the Core libraries committee, it was just about 6 years before the committee formed so you probably don't have records of it, which is why libraries@ is listed as the author. I'm happy to take a more active role in maintaining it. In particular, I was intending to review/comment on https://github.com/haskell/filepath/pulls, and have the intention to add a bunch of patches (https://github.com/ndmitchell/shake/issues/174). Most of the patches are either obviously a good idea (fixing broken code) or improving the docs. The only one which could have any debate surrounding it is the introduction of a new operator -<.>. I don't want to debate that now, but it would be good to get clarification as to whether I should unilaterally add it, or should go through the libraries submission process, or ... Thanks, Neil On Tue, Sep 30, 2014 at 4:17 PM, Andrew Gill wrote: > All, > > I?ve not touched hoc for quite a while. KU now has the resources to take > ownership, if needed. It?s pretty stable, from what I understand, but could > do with the an updated manual. > > Andy Gill > > On Sep 28, 2014, at 1:45 PM, Edward Kmett wrote: > > Herbert: > > Heretofore I'd been treating filepath as owned by Neil Mitchell, but that > statement does sound like he's handed it off to the libraries process, which > would make it a core-libraries issue if he doesn't want to deal with it. > > I'm copying him on this thread to get his opinion. > > I've also copied Andy Gill, to see if he has any opinions on the state of > who owns update responsibility for hpc itself. > > Andy, Neil: Thoughts? > > Thomas: Thanks for forcing this issue to attention. > > -Edward > > On Sun, Sep 28, 2014 at 2:14 PM, Herbert Valerio Riedel > wrote: >> >> On 2014-09-28 at 19:40:25 +0200, Thomas Miedema wrote: >> >> [...] >> >> > Ok, final question: What about filepath and hpc? Their .cabal files list >> > libraries at haskell.org as maintainer, which usually means the Core >> > Libraries >> > Committee. Should filepath be added to that list, and the maintainer for >> > both filepath and hpc be set to the Core Libraries Committee? If not, >> > who >> > maintains filepath? >> >> This is supposed to be an answer, but rather additional data-points: >> >> As far as filepath is concerned: >> >> http://community.haskell.org/~ndm/filepath/ >> >> states >> >> | The library is now part of the core Haskell libraries, and since GHC >> | 6.6.1 has been shipped with all major compilers. While I am the >> | original author, changes are now made through the library submissions >> | process. >> >> as for Hpc, if you look at its changelog over at >> >> http://git.haskell.org/packages/hpc.git/shortlog >> >> it's been effectively maintained by GHC HQ for the last couple of >> years... > > > From ekmett at gmail.com Thu Oct 9 22:16:56 2014 From: ekmett at gmail.com (Edward Kmett) Date: Thu, 9 Oct 2014 18:16:56 -0400 Subject: [core libraries] List of core libraries In-Reply-To: References: <878ul3ehoc.fsf@gmail.com> Message-ID: It is your library as much as you want it to be. As such you can consider yourself as the maintainer and under http://www.haskell.org/haskellwiki/Library_submissions - Changes that simply *widen the API by adding new functions* are a bit of a grey area. It's better to consult the community, because there may be useful feedback about (say) the order of arguments, or the name of the function, or whatnot. On the other hand few clients will actually break if you add a new function to the API. Use your judgment. Here you have a pretty obvious combinator, with one obvious argument ordering I'd assume, so you should be able to do as you see fit. The core libraries committee can help as much or as little as you want us to around filepath. -Edward On Thu, Oct 9, 2014 at 5:56 PM, Neil Mitchell wrote: > I did semi-hand the filepath library over to the Core libraries > committee, it was just about 6 years before the committee formed so > you probably don't have records of it, which is why libraries@ is > listed as the author. I'm happy to take a more active role in > maintaining it. In particular, I was intending to review/comment on > https://github.com/haskell/filepath/pulls, and have the intention to > add a bunch of patches > (https://github.com/ndmitchell/shake/issues/174). Most of the patches > are either obviously a good idea (fixing broken code) or improving the > docs. The only one which could have any debate surrounding it is the > introduction of a new operator -<.>. I don't want to debate that now, > but it would be good to get clarification as to whether I should > unilaterally add it, or should go through the libraries submission > process, or ... > > Thanks, Neil > > > On Tue, Sep 30, 2014 at 4:17 PM, Andrew Gill wrote: > > All, > > > > I?ve not touched hoc for quite a while. KU now has the resources to take > > ownership, if needed. It?s pretty stable, from what I understand, but > could > > do with the an updated manual. > > > > Andy Gill > > > > On Sep 28, 2014, at 1:45 PM, Edward Kmett wrote: > > > > Herbert: > > > > Heretofore I'd been treating filepath as owned by Neil Mitchell, but that > > statement does sound like he's handed it off to the libraries process, > which > > would make it a core-libraries issue if he doesn't want to deal with it. > > > > I'm copying him on this thread to get his opinion. > > > > I've also copied Andy Gill, to see if he has any opinions on the state of > > who owns update responsibility for hpc itself. > > > > Andy, Neil: Thoughts? > > > > Thomas: Thanks for forcing this issue to attention. > > > > -Edward > > > > On Sun, Sep 28, 2014 at 2:14 PM, Herbert Valerio Riedel < > hvriedel at gmail.com> > > wrote: > >> > >> On 2014-09-28 at 19:40:25 +0200, Thomas Miedema wrote: > >> > >> [...] > >> > >> > Ok, final question: What about filepath and hpc? Their .cabal files > list > >> > libraries at haskell.org as maintainer, which usually means the Core > >> > Libraries > >> > Committee. Should filepath be added to that list, and the maintainer > for > >> > both filepath and hpc be set to the Core Libraries Committee? If not, > >> > who > >> > maintains filepath? > >> > >> This is supposed to be an answer, but rather additional data-points: > >> > >> As far as filepath is concerned: > >> > >> http://community.haskell.org/~ndm/filepath/ > >> > >> states > >> > >> | The library is now part of the core Haskell libraries, and since GHC > >> | 6.6.1 has been shipped with all major compilers. While I am the > >> | original author, changes are now made through the library submissions > >> | process. > >> > >> as for Hpc, if you look at its changelog over at > >> > >> http://git.haskell.org/packages/hpc.git/shortlog > >> > >> it's been effectively maintained by GHC HQ for the last couple of > >> years... > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ndmitchell at gmail.com Thu Oct 9 22:38:06 2014 From: ndmitchell at gmail.com (Neil Mitchell) Date: Thu, 9 Oct 2014 23:38:06 +0100 Subject: [core libraries] List of core libraries In-Reply-To: References: <878ul3ehoc.fsf@gmail.com> Message-ID: Great. I think filepath could do with a bit of TLC, and I am happy to do that. There are lots of things that are looking a little crusty around the edges (I don't think the test suite will actually fail in Travis if there is an error, it refers to dead web pages, the README talks a lot about Yhc). I see Herbert and Ian before him have done a reasonable amount of work to keep it in a GHC'able state, and I wouldn't want to cause any difficulties there. So two main questions: * Where/how should I push changes? Should I start with pull requests to the filepath module? Should I clone it to ndmitchell and that become the official repo? Should I get added to the haskell group? * What's the integration with GHC? Does the filepath module get pulled directly into GHC source trees? I see it's in the GHC test suite - is that considered a good idea? I'm a fan of testing my packages to destruction outside the GHC tree, but if people think its valuable it can stay - my main worry is breaking the GHC test suite inadvertently by not updating the expected stdout (which Travis doesn't currently check). Thanks, Neil On Thu, Oct 9, 2014 at 11:16 PM, Edward Kmett wrote: > It is your library as much as you want it to be. As such you can consider > yourself as the maintainer and under > http://www.haskell.org/haskellwiki/Library_submissions > > Changes that simply widen the API by adding new functions are a bit of a > grey area. It's better to consult the community, because there may be useful > feedback about (say) the order of arguments, or the name of the function, or > whatnot. On the other hand few clients will actually break if you add a new > function to the API. Use your judgment. > > Here you have a pretty obvious combinator, with one obvious argument > ordering I'd assume, so you should be able to do as you see fit. > > The core libraries committee can help as much or as little as you want us to > around filepath. > > -Edward > > On Thu, Oct 9, 2014 at 5:56 PM, Neil Mitchell wrote: >> >> I did semi-hand the filepath library over to the Core libraries >> committee, it was just about 6 years before the committee formed so >> you probably don't have records of it, which is why libraries@ is >> listed as the author. I'm happy to take a more active role in >> maintaining it. In particular, I was intending to review/comment on >> https://github.com/haskell/filepath/pulls, and have the intention to >> add a bunch of patches >> (https://github.com/ndmitchell/shake/issues/174). Most of the patches >> are either obviously a good idea (fixing broken code) or improving the >> docs. The only one which could have any debate surrounding it is the >> introduction of a new operator -<.>. I don't want to debate that now, >> but it would be good to get clarification as to whether I should >> unilaterally add it, or should go through the libraries submission >> process, or ... >> >> Thanks, Neil >> >> >> On Tue, Sep 30, 2014 at 4:17 PM, Andrew Gill wrote: >> > All, >> > >> > I?ve not touched hoc for quite a while. KU now has the resources to take >> > ownership, if needed. It?s pretty stable, from what I understand, but >> > could >> > do with the an updated manual. >> > >> > Andy Gill >> > >> > On Sep 28, 2014, at 1:45 PM, Edward Kmett wrote: >> > >> > Herbert: >> > >> > Heretofore I'd been treating filepath as owned by Neil Mitchell, but >> > that >> > statement does sound like he's handed it off to the libraries process, >> > which >> > would make it a core-libraries issue if he doesn't want to deal with it. >> > >> > I'm copying him on this thread to get his opinion. >> > >> > I've also copied Andy Gill, to see if he has any opinions on the state >> > of >> > who owns update responsibility for hpc itself. >> > >> > Andy, Neil: Thoughts? >> > >> > Thomas: Thanks for forcing this issue to attention. >> > >> > -Edward >> > >> > On Sun, Sep 28, 2014 at 2:14 PM, Herbert Valerio Riedel >> > >> > wrote: >> >> >> >> On 2014-09-28 at 19:40:25 +0200, Thomas Miedema wrote: >> >> >> >> [...] >> >> >> >> > Ok, final question: What about filepath and hpc? Their .cabal files >> >> > list >> >> > libraries at haskell.org as maintainer, which usually means the Core >> >> > Libraries >> >> > Committee. Should filepath be added to that list, and the maintainer >> >> > for >> >> > both filepath and hpc be set to the Core Libraries Committee? If not, >> >> > who >> >> > maintains filepath? >> >> >> >> This is supposed to be an answer, but rather additional data-points: >> >> >> >> As far as filepath is concerned: >> >> >> >> http://community.haskell.org/~ndm/filepath/ >> >> >> >> states >> >> >> >> | The library is now part of the core Haskell libraries, and since GHC >> >> | 6.6.1 has been shipped with all major compilers. While I am the >> >> | original author, changes are now made through the library submissions >> >> | process. >> >> >> >> as for Hpc, if you look at its changelog over at >> >> >> >> http://git.haskell.org/packages/hpc.git/shortlog >> >> >> >> it's been effectively maintained by GHC HQ for the last couple of >> >> years... >> > >> > >> > > > From david.feuer at gmail.com Fri Oct 10 05:58:05 2014 From: david.feuer at gmail.com (David Feuer) Date: Fri, 10 Oct 2014 01:58:05 -0400 Subject: Proposal: end lazy IO results with errors/exceptions In-Reply-To: References: Message-ID: I've uploaded this change (with a much more useful error message) as D327 on Phabricator. I have done some very limited testing, and it passes GHC's validation (on Linux), but I would really appreciate if some people who use a lot of lazy IO could test this against their programs to make sure it doesn't produce errors in any cases when it shouldn't. Thanks, David On Mon, Jul 21, 2014 at 4:16 PM, David Feuer wrote: > Currently, > > withFile "foo" hGetContents >>= putStrLn > > prints out an empty line, the better to confuse newbies. > > I propose modifying the lazyRead function in GHC.IO.Handle.Text that > currently reads > > lazyRead :: Handle -> IO String > lazyRead handle = > unsafeInterleaveIO $ > withHandle "hGetContents" handle $ \ handle_ -> do > case haType handle_ of > ClosedHandle -> return (handle_, "") > SemiClosedHandle -> lazyReadBuffered handle handle_ > _ -> ioException > (IOError (Just handle) IllegalOperation "hGetContents" > "illegal handle type" Nothing Nothing) > > to something like > > lazyRead :: Handle -> IO String > lazyRead handle = > unsafeInterleaveIO $ > withHandle "hGetContents" handle $ \ handle_ -> do > case haType handle_ of > ClosedHandle -> return (handle_, error "Forcing the > result of a lazy read led to an attempt to read from a closed > handle.") > SemiClosedHandle -> lazyReadBuffered handle handle_ > _ -> ioException > (IOError (Just handle) IllegalOperation "hGetContents" > "illegal handle type" Nothing Nothing) > > Ideally that error should instead be something to throw an imprecise > exception, but I don't know how to use those yet. I can't personally > see a way for this to break sane, working code, but the folks on #ghc > thought it should be discussed and debated on list. > > David Feuer > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ndmitchell at gmail.com Fri Oct 10 07:15:04 2014 From: ndmitchell at gmail.com (Neil Mitchell) Date: Fri, 10 Oct 2014 08:15:04 +0100 Subject: [core libraries] List of core libraries In-Reply-To: <87lhooxvpr.fsf@gmail.com> References: <878ul3ehoc.fsf@gmail.com> <87lhooxvpr.fsf@gmail.com> Message-ID: > Btw, I'm a bit wondering, why do you think the testsuite's failure won't > mark the Travis-CI build as failed? :) It's a bit hard to know for sure, but my logic is: * https://github.com/haskell/filepath/blob/master/tests/AutoTest.hs#L38 means that the output of the QuickCheck test doesn't cause an exception (as it originally was), but just prints a message about failure * The travis doesn't look at https://github.com/haskell/filepath/blob/master/tests/filepath.stdout So Travis doesn't check the test won't be broken by GHC, and I think without that check it doesn't spot failures. (That's my chain of reasoning, but it's all a little subtle, so could quite easily be wrong!) > I'd suggest to simply add you to the maintainer-team for filepath on > https://github.com/haskell/filepath/ if that's ok for you (in fact, I've > just added you in just in case) Great. >> * What's the integration with GHC? Does the filepath module get pulled >> directly into GHC source trees? I see it's in the GHC test suite - is >> that considered a good idea? > > it's a submodule in ghc.git, and we have an automatic mirroring job > mirroring to git.haskell.org/packages/filepath.git > > And from time to time, we'd update the commit ghc.git points to inside > filepath.git; so you can freely push to master on > https://github.com/haskell/filepath w/o affecting GHC HEAD, only when we > update the filepath gitlink we'd see the effect of it in GHC HEAD. Perfect. I'm sure I'll do something incompatible with the GHC world at some point, but just shout at me when I do (or, if there happens to be a list of the most likely stupid things I might do, let me know). > I think this is mostly a historic artefact, as something Travis wasn't > around when filepath started being used by GHC. Cabal was barely around when filepath started being used by GHC... Cabal test was at least one incompatible iteration as well. > Do you have the means to test filepath on all GHC tier-1 > platforms/archs? (That's the only benefit I currently see with having > the tests as part of GHC's validation testsuite) No, that's valuable, and certainly makes it work keeping. Thanks, Neil From jon.fairbairn at cl.cam.ac.uk Fri Oct 10 09:18:14 2014 From: jon.fairbairn at cl.cam.ac.uk (Jon Fairbairn) Date: Fri, 10 Oct 2014 10:18:14 +0100 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf References: Message-ID: David Feuer writes: > A slight simplification (because I realized the weird thing I was doing > won't actually save any time): > > isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > needle `isSuffixOf` hay = > maybe False > (\fp -> needle == getEndChunk hay fp) > (getFrontPointer needle hay) > where > getEndChunk :: [a] -> [a] -> [a] > getEndChunk (_:hy) (_:fp) = getEndChunk hy fp > getEndChunk hy _ = hy > > getFrontPointer :: [a] -> [a] -> Maybe [a] > getFrontPointer [] hy = Just hy > getFrontPointer _ [] = Nothing > getFrontPointer (_:nd) (_:hy) = getFrontPointer nd hy That seems rather wordy to me. Can we get anywhere starting with a `isSuffixOf` b = a `elem` tails b and transforming? I?m not awake enough to the efficiency implications, but a `isSuffixOf` b = a `elem` (take 1 $ dropWhile (longerThan a) $ tails b) longerThan _ [] = False longerThan [] _ = True longerThan (_:a) (_:b) = longerThan a b looks plausible. > I still haven't heard from anyone about the slight semantic change. To > clarify it slightly, the only aspect that could theoretically be a problem > for somebody is that this reverses the order in which the elements of the > "needle" are compared to the (length needle) elements at the end of the > "haystack". The current implementation compares them from back to front; > this one compares them from front to back. That means that if some elements > in the needle or near the end of the haystack are undefined, there are > cases where this implementation bottoms out when the current one returns > False, and vice versa. This doesn?t bother me. Comparing forwards seems more a ?natural? expectation. -- J?n Fairbairn Jon.Fairbairn at cl.cam.ac.uk http://www.chaos.org.uk/~jf/Stuff-I-dont-want.html (updated 2014-04-05) From david.feuer at gmail.com Fri Oct 10 09:23:45 2014 From: david.feuer at gmail.com (David Feuer) Date: Fri, 10 Oct 2014 05:23:45 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: Message-ID: On Fri, Oct 10, 2014 at 5:18 AM, Jon Fairbairn wrote: > That seems rather wordy to me. Can we get anywhere starting with > > It is rather wordy; I just don't know how to do better. > a `isSuffixOf` b = a `elem` tails b > > and transforming? I?m not awake enough to the efficiency > implications, but > > > a `isSuffixOf` b = a `elem` (take 1 $ dropWhile (longerThan a) $ tails > b) > > longerThan _ [] = False > longerThan [] _ = True > longerThan (_:a) (_:b) = longerThan a b > > looks plausible. > That looks bad. The implementation I gave is something like O(m+n), whereas yours looks something like O(m*n). -------------- next part -------------- An HTML attachment was scrubbed... URL: From fox at ucw.cz Fri Oct 10 12:34:53 2014 From: fox at ucw.cz (Milan Straka) Date: Fri, 10 Oct 2014 14:34:53 +0200 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: Message-ID: <20141010123453.GA14905@auryn.cz> Hi all, > -----Original message----- > From: David Feuer > Sent: 10 Oct 2014, 05:23 > > On Fri, Oct 10, 2014 at 5:18 AM, Jon Fairbairn > wrote: > > > That seems rather wordy to me. Can we get anywhere starting with > > > > > It is rather wordy; I just don't know how to do better. What about something like the following? It uses exactly the same algorithm, it just avoids the maybe combinator and Maybe internal result, and renames stuff: isSuffixOf :: (Eq a) => [a] -> [a] -> Bool [] `isSuffixOf` _ = True needle `isSuffixOf` hay = subtract_and_compare needle hay where subtract_and_compare [] diff = skip_and_compare diff hay subtract_and_compare _ [] = False -- needle longer than hay subtract_and_compare (n:ns) (h:hs) = subtract_and_compare ns hs skip_and_compare [] suffix = needle == suffix skip_and_compare _ [] = True -- first argument must also be [] skip_and_compare (d:ds) (s:ss) = skip_and_compare ds ss The redundant skip_and_compare case is there just for completeness and readability. Cheers, Milan From jwlato at gmail.com Fri Oct 10 14:48:20 2014 From: jwlato at gmail.com (John Lato) Date: Fri, 10 Oct 2014 07:48:20 -0700 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: <20141010123453.GA14905@auryn.cz> References: <20141010123453.GA14905@auryn.cz> Message-ID: I think David's proposed definition is the easiest to read form with good performance so far. As to definedness, the change in semantics doesn't matter to me. But I think calling isSuffixOf on possibly infinite lists is a bad idea anyway. John L. On Oct 10, 2014 5:35 AM, "Milan Straka" wrote: > > Hi all, > > > -----Original message----- > > From: David Feuer > > Sent: 10 Oct 2014, 05:23 > > > > On Fri, Oct 10, 2014 at 5:18 AM, Jon Fairbairn < jon.fairbairn at cl.cam.ac.uk> > > wrote: > > > > > That seems rather wordy to me. Can we get anywhere starting with > > > > > > > > It is rather wordy; I just don't know how to do better. > > What about something like the following? It uses exactly the same > algorithm, it just avoids the maybe combinator and Maybe internal > result, and renames stuff: > > isSuffixOf :: (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > needle `isSuffixOf` hay = subtract_and_compare needle hay > where subtract_and_compare [] diff = skip_and_compare diff hay > subtract_and_compare _ [] = False -- needle longer than hay > subtract_and_compare (n:ns) (h:hs) = subtract_and_compare ns hs > > skip_and_compare [] suffix = needle == suffix > skip_and_compare _ [] = True -- first argument must also be [] > skip_and_compare (d:ds) (s:ss) = skip_and_compare ds ss > > The redundant skip_and_compare case is there just for completeness and > readability. > > Cheers, > Milan > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Fri Oct 10 16:23:54 2014 From: david.feuer at gmail.com (David Feuer) Date: Fri, 10 Oct 2014 12:23:54 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> Message-ID: I wouldn't say calling it on a possibly infinite list would necessarily be the wisest thing, but supporting an infinite "needle" with a finite "haystack" comes for free with the forward traversal. Unlike inInfixOf, the extra implementation flexibility gained by specifying that the needle is finite has no serious potential to allow fancy algorithms to improve efficiency. The real odd semantic duck, I think, is the special case for an empty needle, because it is lazier than one might expect. In particular, I would expect that isSuffixOf [] undefined would be False, because undefined is not a []-terminated list. Leaving *that* unspecified would make a lot of sense to me. As for simplicity of form, orb__ came up with a version that uses Either instead of Maybe to take advantage of the similarity of two phases to get away with just one helper function, but I think that approach is much harder to understand. On Oct 10, 2014 10:48 AM, "John Lato" wrote: > I think David's proposed definition is the easiest to read form with good > performance so far. > > As to definedness, the change in semantics doesn't matter to me. But I > think calling isSuffixOf on possibly infinite lists is a bad idea anyway. > > John L. > > On Oct 10, 2014 5:35 AM, "Milan Straka" wrote: > > > > Hi all, > > > > > -----Original message----- > > > From: David Feuer > > > Sent: 10 Oct 2014, 05:23 > > > > > > On Fri, Oct 10, 2014 at 5:18 AM, Jon Fairbairn < > jon.fairbairn at cl.cam.ac.uk> > > > wrote: > > > > > > > That seems rather wordy to me. Can we get anywhere starting with > > > > > > > > > > > It is rather wordy; I just don't know how to do better. > > > > What about something like the following? It uses exactly the same > > algorithm, it just avoids the maybe combinator and Maybe internal > > result, and renames stuff: > > > > isSuffixOf :: (Eq a) => [a] -> [a] -> Bool > > [] `isSuffixOf` _ = True > > needle `isSuffixOf` hay = subtract_and_compare needle hay > > where subtract_and_compare [] diff = skip_and_compare diff hay > > subtract_and_compare _ [] = False -- needle longer than hay > > subtract_and_compare (n:ns) (h:hs) = subtract_and_compare ns hs > > > > skip_and_compare [] suffix = needle == suffix > > skip_and_compare _ [] = True -- first argument must also be [] > > skip_and_compare (d:ds) (s:ss) = skip_and_compare ds ss > > > > The redundant skip_and_compare case is there just for completeness and > > readability. > > > > Cheers, > > Milan > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://www.haskell.org/mailman/listinfo/libraries > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Fri Oct 10 16:39:08 2014 From: david.feuer at gmail.com (David Feuer) Date: Fri, 10 Oct 2014 12:39:08 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> Message-ID: I accidentally hit "send" before finishing this message. I *think* my version is probably a little easier to understand than Milan's but it also seems possible that Milan's could take the lead with some more inspired variable names. I also wish I knew a way to avoid the bogus pattern in skip_and_compare (and my equivalent), but I haven't been able to do so. On Oct 10, 2014 12:23 PM, "David Feuer" wrote: > I wouldn't say calling it on a possibly infinite list would necessarily be > the wisest thing, but supporting an infinite "needle" with a finite > "haystack" comes for free with the forward traversal. Unlike inInfixOf, the > extra implementation flexibility gained by specifying that the needle is > finite has no serious potential to allow fancy algorithms to improve > efficiency. > > The real odd semantic duck, I think, is the special case for an empty > needle, because it is lazier than one might expect. In particular, I would > expect that isSuffixOf [] undefined would be False, because undefined is > not a []-terminated list. Leaving *that* unspecified would make a lot of > sense to me. > > As for simplicity of form, orb__ came up with a version that uses Either > instead of Maybe to take advantage of the similarity of two phases to get > away with just one helper function, but I think that approach is much > harder to understand. > On Oct 10, 2014 10:48 AM, "John Lato" wrote: > >> I think David's proposed definition is the easiest to read form with good >> performance so far. >> >> As to definedness, the change in semantics doesn't matter to me. But I >> think calling isSuffixOf on possibly infinite lists is a bad idea anyway. >> >> John L. >> >> On Oct 10, 2014 5:35 AM, "Milan Straka" wrote: >> > >> > Hi all, >> > >> > > -----Original message----- >> > > From: David Feuer >> > > Sent: 10 Oct 2014, 05:23 >> > > >> > > On Fri, Oct 10, 2014 at 5:18 AM, Jon Fairbairn < >> jon.fairbairn at cl.cam.ac.uk> >> > > wrote: >> > > >> > > > That seems rather wordy to me. Can we get anywhere starting with >> > > > >> > > > >> > > It is rather wordy; I just don't know how to do better. >> > >> > What about something like the following? It uses exactly the same >> > algorithm, it just avoids the maybe combinator and Maybe internal >> > result, and renames stuff: >> > >> > isSuffixOf :: (Eq a) => [a] -> [a] -> Bool >> > [] `isSuffixOf` _ = True >> > needle `isSuffixOf` hay = subtract_and_compare needle hay >> > where subtract_and_compare [] diff = skip_and_compare diff hay >> > subtract_and_compare _ [] = False -- needle longer than hay >> > subtract_and_compare (n:ns) (h:hs) = subtract_and_compare ns hs >> > >> > skip_and_compare [] suffix = needle == suffix >> > skip_and_compare _ [] = True -- first argument must also be [] >> > skip_and_compare (d:ds) (s:ss) = skip_and_compare ds ss >> > >> > The redundant skip_and_compare case is there just for completeness and >> > readability. >> > >> > Cheers, >> > Milan >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://www.haskell.org/mailman/listinfo/libraries >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From ky3 at atamo.com Sat Oct 11 09:13:30 2014 From: ky3 at atamo.com (Kim-Ee Yeoh) Date: Sat, 11 Oct 2014 16:13:30 +0700 Subject: Optimizing isSuffixOf (was Re: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf) Message-ID: On Fri, Oct 10, 2014 at 4:18 PM, Jon Fairbairn wrote: > That seems rather wordy to me. Can we get anywhere starting with > > a `isSuffixOf` b = a `elem` tails b > > and transforming? Is it only about wordiness & syntax? With the original a `isSuffixOf` b = reverse a `isPrefixOf` reverse b and with Jon's a `isSuffixOf` b = a `elem` tails b I'm completely convinced of the correctness, modulo that of the referenced functions. Moreover, the conviction was obtained cheaply. My finite neurons are saved for the greater task at hand. The proposal on the table snatches away that providence. I have to take it on the authority of others that it's correct. Rust recently exposed a bug in their string matching function. It's their version of Data.List.isInfixOf. See http://www.wabbo.org/blog/2014/22aug_on_bananas.html These days I point all my colleagues and friends to this article as a classic case of premature optimization. But I understand that some folks prefer their computations always rapid, if sometimes wrong. David, is there an application underlying the need for isSuffixOf speed? You might want to look into the ByteString libraries for your optimization efforts. Over there, performance is several notches up in priority. -- Kim-Ee -------------- next part -------------- An HTML attachment was scrubbed... URL: From abela at chalmers.se Sat Oct 11 09:57:45 2014 From: abela at chalmers.se (Andreas Abel) Date: Sat, 11 Oct 2014 11:57:45 +0200 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> Message-ID: <5438FF19.3040607@chalmers.se> David, the essence of your idea seems mutually drop the correct number of elements from needle and hay and then compare for equality. Here is a concise implementation of your idea in terms of drop: isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool [] `isSuffixOf` _ = True xs `isSuffixOf` ys = xs == drop (length (drop (length xs) ys)) ys This can be further simplified to isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool [] `isSuffixOf` _ = True xs `isSuffixOf` ys = xs == drop (length ys - length xs) ys which is a very easy to understand program, I think, without need to reverse lists. On 10.10.2014 18:39, David Feuer wrote: > I accidentally hit "send" before finishing this message. I *think* my > version is probably a little easier to understand than Milan's but it > also seems possible that Milan's could take the lead with some more > inspired variable names. I also wish I knew a way to avoid the bogus > pattern in skip_and_compare (and my equivalent), but I haven't been able > to do so. > > On Oct 10, 2014 12:23 PM, "David Feuer" > wrote: > > I wouldn't say calling it on a possibly infinite list would > necessarily be the wisest thing, but supporting an infinite "needle" > with a finite "haystack" comes for free with the forward traversal. > Unlike inInfixOf, the extra implementation flexibility gained by > specifying that the needle is finite has no serious potential to > allow fancy algorithms to improve efficiency. > > The real odd semantic duck, I think, is the special case for an > empty needle, because it is lazier than one might expect. In > particular, I would expect that isSuffixOf [] undefined would be > False, because undefined is not a []-terminated list. Leaving *that* > unspecified would make a lot of sense to me. > > As for simplicity of form, orb__ came up with a version that uses > Either instead of Maybe to take advantage of the similarity of two > phases to get away with just one helper function, but I think that > approach is much harder to understand. > > On Oct 10, 2014 10:48 AM, "John Lato" > wrote: > > I think David's proposed definition is the easiest to read form > with good performance so far. > > As to definedness, the change in semantics doesn't matter to > me. But I think calling isSuffixOf on possibly infinite lists > is a bad idea anyway. > > John L. > > On Oct 10, 2014 5:35 AM, "Milan Straka" > wrote: > > > > Hi all, > > > > > -----Original message----- > > > From: David Feuer > > > > Sent: 10 Oct 2014, 05:23 > > > > > > On Fri, Oct 10, 2014 at 5:18 AM, Jon Fairbairn > > > > > wrote: > > > > > > > That seems rather wordy to me. Can we get anywhere > starting with > > > > > > > > > > > It is rather wordy; I just don't know how to do better. > > > > What about something like the following? It uses exactly the same > > algorithm, it just avoids the maybe combinator and Maybe internal > > result, and renames stuff: > > > > isSuffixOf :: (Eq a) => [a] -> [a] -> Bool > > [] `isSuffixOf` _ = True > > needle `isSuffixOf` hay = subtract_and_compare needle hay > > where subtract_and_compare [] diff = skip_and_compare diff hay > > subtract_and_compare _ [] = False -- needle longer > than hay > > subtract_and_compare (n:ns) (h:hs) = > subtract_and_compare ns hs > > > > skip_and_compare [] suffix = needle == suffix > > skip_and_compare _ [] = True -- first argument must > also be [] > > skip_and_compare (d:ds) (s:ss) = skip_and_compare ds ss > > > > The redundant skip_and_compare case is there just for > completeness and > > readability. > > > > Cheers, > > Milan > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://www.haskell.org/mailman/listinfo/libraries > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From david.feuer at gmail.com Sat Oct 11 12:47:20 2014 From: david.feuer at gmail.com (David Feuer) Date: Sat, 11 Oct 2014 08:47:20 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: <5438FF19.3040607@chalmers.se> References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> Message-ID: It can be, but your way traverses the entire haystack *twice*. The memory needs are equivalent to the reversing version, which I consider unacceptable. On Sat, Oct 11, 2014 at 5:57 AM, Andreas Abel wrote: > David, the essence of your idea seems mutually drop the correct number of > elements from needle and hay and then compare for equality. Here is a > concise implementation of your idea in terms of drop: > > isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > xs `isSuffixOf` ys = xs == drop (length (drop (length xs) ys)) ys > > This can be further simplified to > > isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > xs `isSuffixOf` ys = xs == drop (length ys - length xs) ys > > which is a very easy to understand program, I think, without need to > reverse lists. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sat Oct 11 21:10:33 2014 From: david.feuer at gmail.com (David Feuer) Date: Sat, 11 Oct 2014 17:10:33 -0400 Subject: Discussion: Add safeWithFile function Message-ID: Some care is required to use withFile properly with lazy IO, and people sometimes get it wrong. In some cases, readFile is a suitable replacement. In other cases, however, it may be necessary to ensure the file gets closed in a timely manner, and it may not be necessary to read the whole file. The following seems to do the trick: safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a safeWithFile name mode f = withFile name mode $ f >=> (return $!!) Sample use: *SafeWithFile> safeWithFile "SafeWithFile.hs" ReadMode hGetContents >>= putStr module SafeWithFile (safeWithFile) where import Control.DeepSeq import System.IO import Control.Monad safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a safeWithFile name mode f = withFile name mode $ f >=> (return $!!) -------------- next part -------------- An HTML attachment was scrubbed... URL: From felipe.lessa at gmail.com Sat Oct 11 22:15:08 2014 From: felipe.lessa at gmail.com (Felipe Lessa) Date: Sat, 11 Oct 2014 19:15:08 -0300 Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: <5439ABEC.9000707@gmail.com> A priori, I'm -1 on this proposal. It seems too ad hoc, and the motivation does not seem compelling. It also may be confusing, like "when is withFile unsafe?"-confusing. -- Felipe. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From abela at chalmers.se Sun Oct 12 14:14:45 2014 From: abela at chalmers.se (Andreas Abel) Date: Sun, 12 Oct 2014 16:14:45 +0200 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> Message-ID: <543A8CD5.8030603@chalmers.se> Well, you also traverse the haystack twice, in your getEndChunk function you simultaneously traverse the haystack and a (shared) copy of it. Why is this so much better? I guess without data (timings, heap-profiles) we do not get further here. On 11.10.2014 14:47, David Feuer wrote: > It can be, but your way traverses the entire haystack *twice*. The > memory needs are equivalent to the reversing version, which I consider > unacceptable. I do not understand this comment. reverse needs O(n) memory, length O(1). Cheers, Andreas > On Sat, Oct 11, 2014 at 5:57 AM, Andreas Abel > wrote: > > David, the essence of your idea seems mutually drop the correct > number of elements from needle and hay and then compare for > equality. Here is a concise implementation of your idea in terms of > drop: > > isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > xs `isSuffixOf` ys = xs == drop (length (drop (length xs) ys)) ys > > This can be further simplified to > > isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > xs `isSuffixOf` ys = xs == drop (length ys - length xs) ys > > which is a very easy to understand program, I think, without need to > reverse lists. > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From david.feuer at gmail.com Sun Oct 12 15:40:43 2014 From: david.feuer at gmail.com (David Feuer) Date: Sun, 12 Oct 2014 11:40:43 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: <543A8CD5.8030603@chalmers.se> References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> Message-ID: The haystack and the shared copy are only a needle's-length apart. The first stage traverses H and N until one of them runs out, holding a copy of the beginning of each. This requires at most O(min{|H|, |N|}) additional memory (the original needle and the needle-length prefix of the haystack). Assuming we didn't run out of haystack before we ran out of needle (which assumption seems generally likely), we proceed to the next step, traversing H and (drop |N| H) together. During this phase we hold O(|N|) additional memory: the needle itself and the needle-length portion of the longer of the two haystack remnants we hold. Note that in the second phase, we *don't* hold on to the beginning of the haystack, because we will never need it again! Then in the final phase, when the shorter haystack remnant has run out, we still have the same O(|N|) memory, which is now the needle itself and the needle-length suffix of the haystack, and (==) traverses them both together. Thus the total additional memory residency for this algorithm is O(min {|H|, |N|}). Using the length approach requires that you hold the beginning of the haystack for traversal while running length. To put it another way, you force the entire spine of the haystack to run length, and then start from the beginning. If the haystack is produced lazily, this potentially requires O(|H|) extra memory. Since you also check the length of the needle, your total additional memory comes to O(max {|H|, |N|}). I apologize if my horrid variable names obscured what goes on in the algorithm I described. On Sun, Oct 12, 2014 at 10:14 AM, Andreas Abel wrote: > Well, you also traverse the haystack twice, in your getEndChunk function > you simultaneously traverse the haystack and a (shared) copy of it. Why is > this so much better? > > I guess without data (timings, heap-profiles) we do not get further here. > > On 11.10.2014 14:47, David Feuer wrote: > >> It can be, but your way traverses the entire haystack *twice*. The >> memory needs are equivalent to the reversing version, which I consider >> unacceptable. >> > > I do not understand this comment. reverse needs O(n) memory, length O(1). > > Cheers, > Andreas > > On Sat, Oct 11, 2014 at 5:57 AM, Andreas Abel > > wrote: >> >> David, the essence of your idea seems mutually drop the correct >> number of elements from needle and hay and then compare for >> equality. Here is a concise implementation of your idea in terms of >> drop: >> >> isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool >> [] `isSuffixOf` _ = True >> xs `isSuffixOf` ys = xs == drop (length (drop (length xs) ys)) ys >> >> This can be further simplified to >> >> isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool >> [] `isSuffixOf` _ = True >> xs `isSuffixOf` ys = xs == drop (length ys - length xs) ys >> >> which is a very easy to understand program, I think, without need to >> reverse lists. >> >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > > -- > Andreas Abel <>< Du bist der geliebte Mensch. > > Department of Computer Science and Engineering > Chalmers and Gothenburg University, Sweden > > andreas.abel at gu.se > http://www2.tcs.ifi.lmu.de/~abel/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ollie at ocharles.org.uk Sun Oct 12 15:58:02 2014 From: ollie at ocharles.org.uk (Oliver Charles) Date: Sun, 12 Oct 2014 16:58:02 +0100 Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: Where are you suggesting this library goes? Your `safeWithFile` needs `NFData`, but that's in `deepseq` which isn't a dependency of `base`. - ocharles On Sat, Oct 11, 2014 at 10:10 PM, David Feuer wrote: > Some care is required to use withFile properly with lazy IO, and people > sometimes get it wrong. In some cases, readFile is a suitable replacement. > In other cases, however, it may be necessary to ensure the file gets closed > in a timely manner, and it may not be necessary to read the whole file. The > following seems to do the trick: > > safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a > safeWithFile name mode f = withFile name mode $ f >=> (return $!!) > > > Sample use: > > *SafeWithFile> safeWithFile "SafeWithFile.hs" ReadMode hGetContents >>= > putStr > module SafeWithFile (safeWithFile) where > import Control.DeepSeq > import System.IO > import Control.Monad > > safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a > safeWithFile name mode f = withFile name mode $ f >=> (return $!!) > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From abela at chalmers.se Sun Oct 12 16:02:54 2014 From: abela at chalmers.se (Andreas Abel) Date: Sun, 12 Oct 2014 18:02:54 +0200 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> Message-ID: <543AA62E.8080403@chalmers.se> If you talk about "additional memory" you assume that after `xs isSuffix ys`, ys is no longer needed. Is this the typical use case? At least not in the Agda codebase, according to my quick grep... ./Packaging/Database.hs: dbEntries = filter (".conf" `isSuffixOf`) filePaths ./TypeChecking/Monad/Open.hs: unless (ctx `isSuffixOf` ctx') $ fail $ "thing out of context (" ++ show ctx ++ " is not a sub context of " ++ show ctx' ++ ")" ./Interaction/Options.hs: isLiterate file = ".lagda" `isSuffixOf` file ./Syntax/Parser.hs: if "lagda" `isSuffixOf` filePath file then As I said, optimizations should be backed by benchmarks, especially when trading a perspicuous implementation for a more complicated one... On 12.10.2014 17:40, David Feuer wrote: > The haystack and the shared copy are only a needle's-length apart. The > first stage traverses H and N until one of them runs out, holding a copy > of the beginning of each. This requires at most O(min{|H|, |N|}) > additional memory (the original needle and the needle-length prefix of > the haystack). Assuming we didn't run out of haystack before we ran out > of needle (which assumption seems generally likely), we proceed to the > next step, traversing H and (drop |N| H) together. During this phase we > hold O(|N|) additional memory: the needle itself and the needle-length > portion of the longer of the two haystack remnants we hold. Note that in > the second phase, we *don't* hold on to the beginning of the haystack, > because we will never need it again! Then in the final phase, when the > shorter haystack remnant has run out, we still have the same O(|N|) > memory, which is now the needle itself and the needle-length suffix of > the haystack, and (==) traverses them both together. Thus the total > additional memory residency for this algorithm is O(min {|H|, |N|}). > Using the length approach requires that you hold the beginning of the > haystack for traversal while running length. To put it another way, you > force the entire spine of the haystack to run length, and then start > from the beginning. If the haystack is produced lazily, this potentially > requires O(|H|) extra memory. Since you also check the length of the > needle, your total additional memory comes to O(max {|H|, |N|}). I > apologize if my horrid variable names obscured what goes on in the > algorithm I described. > > On Sun, Oct 12, 2014 at 10:14 AM, Andreas Abel > wrote: > > Well, you also traverse the haystack twice, in your getEndChunk > function you simultaneously traverse the haystack and a (shared) > copy of it. Why is this so much better? > > I guess without data (timings, heap-profiles) we do not get further > here. > > On 11.10.2014 14:47, David Feuer wrote: > > It can be, but your way traverses the entire haystack *twice*. The > memory needs are equivalent to the reversing version, which I > consider > unacceptable. > > > I do not understand this comment. reverse needs O(n) memory, length > O(1). > > Cheers, > Andreas > > On Sat, Oct 11, 2014 at 5:57 AM, Andreas Abel > >> wrote: > > David, the essence of your idea seems mutually drop the correct > number of elements from needle and hay and then compare for > equality. Here is a concise implementation of your idea in > terms of > drop: > > isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > xs `isSuffixOf` ys = xs == drop (length (drop (length xs) > ys)) ys > > This can be further simplified to > > isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > xs `isSuffixOf` ys = xs == drop (length ys - length xs) ys > > which is a very easy to understand program, I think, > without need to > reverse lists. > > > > _________________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/__mailman/listinfo/libraries > > > > > -- > Andreas Abel <>< Du bist der geliebte Mensch. > > Department of Computer Science and Engineering > Chalmers and Gothenburg University, Sweden > > andreas.abel at gu.se > http://www2.tcs.ifi.lmu.de/~__abel/ > > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From emertens at gmail.com Sun Oct 12 16:05:45 2014 From: emertens at gmail.com (Eric Mertens) Date: Sun, 12 Oct 2014 09:05:45 -0700 Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: -1 This feels particularly ad-hoc and sets a strange precedent for "safe" functions in base. The overall better solution is to stop mixing lazy IO with withFile. In the case that someone absolutely must have this, a local definition will be best for other purple reading the code. On Oct 11, 2014 2:11 PM, "David Feuer" wrote: > Some care is required to use withFile properly with lazy IO, and people > sometimes get it wrong. In some cases, readFile is a suitable replacement. > In other cases, however, it may be necessary to ensure the file gets closed > in a timely manner, and it may not be necessary to read the whole file. The > following seems to do the trick: > > safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a > safeWithFile name mode f = withFile name mode $ f >=> (return $!!) > > > Sample use: > > *SafeWithFile> safeWithFile "SafeWithFile.hs" ReadMode hGetContents >>= > putStr > module SafeWithFile (safeWithFile) where > import Control.DeepSeq > import System.IO > import Control.Monad > > safeWithFile :: (NFData a) => String -> IOMode -> (Handle -> IO a) -> IO a > safeWithFile name mode f = withFile name mode $ f >=> (return $!!) > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Sun Oct 12 16:14:22 2014 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Sun, 12 Oct 2014 18:14:22 +0200 (CEST) Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: On Sun, 12 Oct 2014, Oliver Charles wrote: > Where are you suggesting this library goes? Your `safeWithFile` needs `NFData`, but that's in `deepseq` which > isn't a dependency of `base`. It would certainly be located in 'deepseq' or a dependent library. Maybe Control.DeepSeq.IO.withFile would be good. Then it would be clear, that it is just a deepseq variant of withFile. I would not like the name safeWithFile, because withFile is already safe. It's hGetContents that is unsafe. From jwlato at gmail.com Sun Oct 12 23:32:05 2014 From: jwlato at gmail.com (John Lato) Date: Mon, 13 Oct 2014 07:32:05 +0800 Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: I would support adding this function under the name `withFile`, in a new module exported by the deepseq package, as Henning seems to be suggesting. I don't think it's particularly important, but this pattern arises often enough that I think it's worthwhile. John L. On Mon, Oct 13, 2014 at 12:14 AM, Henning Thielemann < lemming at henning-thielemann.de> wrote: > > On Sun, 12 Oct 2014, Oliver Charles wrote: > > Where are you suggesting this library goes? Your `safeWithFile` needs >> `NFData`, but that's in `deepseq` which >> isn't a dependency of `base`. >> > > It would certainly be located in 'deepseq' or a dependent library. Maybe > Control.DeepSeq.IO.withFile would be good. Then it would be clear, that it > is just a deepseq variant of withFile. > > I would not like the name safeWithFile, because withFile is already safe. > It's hGetContents that is unsafe. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Mon Oct 13 02:32:28 2014 From: david.feuer at gmail.com (David Feuer) Date: Sun, 12 Oct 2014 22:32:28 -0400 Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: I think a lot of people have raised a lot of important concerns. Henning's point, I think, is particularly enlightening: "I would not like the name safeWithFile, because withFile is already safe. It's hGetContents that is unsafe." It also composes very poorly?using the contents of more than one file to compute a result will lead to a double application of deepseq. I'm not sure how to address those concerns. One possible path is to have a safeHGetContents, along with RULES in Control.DeepSeq to attempt to erase the double deepseq. I would support adding this function under the name `withFile`, in a new module exported by the deepseq package, as Henning seems to be suggesting. I don't think it's particularly important, but this pattern arises often enough that I think it's worthwhile. John L. On Mon, Oct 13, 2014 at 12:14 AM, Henning Thielemann < lemming at henning-thielemann.de> wrote: > > On Sun, 12 Oct 2014, Oliver Charles wrote: > > Where are you suggesting this library goes? Your `safeWithFile` needs >> `NFData`, but that's in `deepseq` which >> isn't a dependency of `base`. >> > > It would certainly be located in 'deepseq' or a dependent library. Maybe > Control.DeepSeq.IO.withFile would be good. Then it would be clear, that it > is just a deepseq variant of withFile. > > I would not like the name safeWithFile, because withFile is already safe. > It's hGetContents that is unsafe. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > _______________________________________________ Libraries mailing list Libraries at haskell.org http://www.haskell.org/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Mon Oct 13 07:09:52 2014 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Mon, 13 Oct 2014 09:09:52 +0200 (CEST) Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: On Sun, 12 Oct 2014, David Feuer wrote: > One possible path is to have a safeHGetContents, along with RULES in > Control.DeepSeq to attempt to erase the double deepseq. Is safeHGetContents the same as http://hackage.haskell.org/package/strict-0.3.2/docs/System-IO-Strict.html#v:hGetContents ? From david.feuer at gmail.com Mon Oct 13 11:57:38 2014 From: david.feuer at gmail.com (David Feuer) Date: Mon, 13 Oct 2014 07:57:38 -0400 Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: I was thinking safeHGetContents :: (NFData a) => Handle -> (String -> a) -> IO a and/or safeHGetContents :: (NFData a) => Handle -> (String -> IO a) -> IO a and/or something more explicitly targeting multiple handles (which I think there must be a nice way to do, somehow!). On Mon, Oct 13, 2014 at 3:09 AM, Henning Thielemann < lemming at henning-thielemann.de> wrote: > > On Sun, 12 Oct 2014, David Feuer wrote: > > One possible path is to have a safeHGetContents, along with RULES in >> Control.DeepSeq to attempt to erase the double deepseq. >> > > Is safeHGetContents the same as > > http://hackage.haskell.org/package/strict-0.3.2/docs/ > System-IO-Strict.html#v:hGetContents > > ? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Mon Oct 13 12:55:19 2014 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Mon, 13 Oct 2014 14:55:19 +0200 (CEST) Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: On Mon, 13 Oct 2014, David Feuer wrote: > I was thinking > > safeHGetContents :: (NFData a) => Handle -> (String -> a) -> IO a > > and/or > > safeHGetContents :: (NFData a) => Handle -> (String -> IO a) -> IO a > > and/or something more explicitly targeting multiple handles (which I think there must be a nice way to do, > somehow!). I see. Then a better name might be DeepSeq.IO.withContents or DeepSeq.IO.withFileContents or DeepSeq.IO.hWithContents I still think, that 'safe' is not a good part of a Haskell function name, because 'safe' should be the default. If at all, we could rename hGetContents to unsafeHGetContents. A nested call to withContents would still run deepseq twice, right? From david.feuer at gmail.com Mon Oct 13 13:08:02 2014 From: david.feuer at gmail.com (David Feuer) Date: Mon, 13 Oct 2014 09:08:02 -0400 Subject: Discussion: Add safeWithFile function In-Reply-To: References: Message-ID: On Oct 13, 2014 8:55 AM, "Henning Thielemann" wrote: > A nested call to withContents would still run deepseq twice, right? With the ways I've figured out so far, yes, but I bet someone else can find a better way. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mail at nh2.me Mon Oct 13 15:34:17 2014 From: mail at nh2.me (=?UTF-8?B?TmlrbGFzIEhhbWLDvGNoZW4=?=) Date: Mon, 13 Oct 2014 17:34:17 +0200 Subject: Proposal: Add isSubsequenceOf to Data.List Message-ID: <543BF0F9.9050905@nh2.me> Data.List has `subsequences`, calculating all subsequences of a list, but it doesn't provide a function to check whether a list is a subsequence of another list. `isSubsequenceOf` would go into the "Predicates" section (http://hackage.haskell.org/package/base-4.7.0.1/docs/Data-List.html#g:12) which already contains: * isPrefixOf (dual of inits) * isSuffixOf (dual of tails) * isInfixOf With this proposal, we would add * isSubsequenceOf (dual of subsequences) Suggested implementation: -- | `isSubsequenceOf a b`: Checks if a is a subsequence of b. isSubsequenceOf :: (Eq a) => [a] -> [a] -> Bool isSubsequenceOf [] _ = True isSubsequenceOf _ [] = False isSubsequenceOf a@(x:a') (y:b) | x == y = isSubsequenceOf a' b | otherwise = isSubsequenceOf a b Niklas From david.feuer at gmail.com Mon Oct 13 18:17:01 2014 From: david.feuer at gmail.com (David Feuer) Date: Mon, 13 Oct 2014 14:17:01 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: <543AA62E.8080403@chalmers.se> References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> Message-ID: I've done the benchmarks and the results are clear: the implementation I gave is faster than the one you gave and the one in Data.List in all cases. Yours is usually faster than the one in Data.List, but slower for very short lists. Test code: needles = [ ("shortNeedle", ".exe") ,("longNeedle", "And who by fire? Who by water? Who in the sunshine? Who in the nighttime?")] haystacks = [ ("shortHaystack", "C:\\Program Files\\Windows\\Dunno.exe") ,("longHaystack", take 10000 $ map toEnum $ iterate (\x -> (x*131) .&. 0xFFFF) 7)] impls = [("lib", L.isSuffixOf), ("Feuer", isSuffixOf), ("Abel", isSuffixOfA)] tests = [("simple", (\impl (needle,haystack) -> fromEnum $ needle `impl` haystack)), ("use", (\impl (needle,haystack) -> if needle `impl` haystack then sum (map fromEnum haystack) else product (map fromEnum haystack)))] main = defaultMain [ bgroup (unwords [fst test, fst needle, "in", fst haystack]) [bench (fst impl) $ whnf (snd test $ snd impl) (snd needle, snd haystack) | impl <- impls] | test <- tests, needle <- needles, haystack <- haystacks] Results: benchmarking simple shortNeedle in shortHaystack/lib time 244.6 ns (243.9 ns .. 245.6 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 245.2 ns (244.8 ns .. 246.5 ns) std dev 2.030 ns (950.4 ps .. 4.378 ns) benchmarking simple shortNeedle in shortHaystack/Feuer time 234.5 ns (234.1 ns .. 235.1 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 234.6 ns (234.2 ns .. 235.3 ns) std dev 1.628 ns (678.1 ps .. 2.758 ns) benchmarking simple shortNeedle in shortHaystack/Abel time 268.1 ns (267.8 ns .. 268.4 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 268.0 ns (267.8 ns .. 268.4 ns) std dev 947.8 ps (538.1 ps .. 1.668 ns) benchmarking simple shortNeedle in longHaystack/lib time 100.5 ?s (100.2 ?s .. 100.9 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 100.8 ?s (100.5 ?s .. 101.4 ?s) std dev 1.511 ?s (1.035 ?s .. 2.095 ?s) benchmarking simple shortNeedle in longHaystack/Feuer time 55.66 ?s (55.61 ?s .. 55.73 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 55.68 ?s (55.63 ?s .. 55.79 ?s) std dev 222.0 ns (128.7 ns .. 415.0 ns) benchmarking simple shortNeedle in longHaystack/Abel time 94.60 ?s (94.39 ?s .. 94.94 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 94.51 ?s (94.44 ?s .. 94.68 ?s) std dev 332.8 ns (183.6 ns .. 617.7 ns) benchmarking simple longNeedle in shortHaystack/lib time 480.6 ns (480.2 ns .. 481.1 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 480.6 ns (480.1 ns .. 481.6 ns) std dev 2.217 ns (1.025 ns .. 4.032 ns) benchmarking simple longNeedle in shortHaystack/Feuer time 187.0 ns (186.8 ns .. 187.2 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 187.0 ns (186.8 ns .. 187.4 ns) std dev 922.0 ps (427.3 ps .. 1.598 ns) benchmarking simple longNeedle in shortHaystack/Abel time 340.9 ns (339.4 ns .. 343.3 ns) 1.000 R? (0.999 R? .. 1.000 R?) mean 345.0 ns (341.6 ns .. 351.0 ns) std dev 14.40 ns (9.622 ns .. 20.77 ns) variance introduced by outliers: 60% (severely inflated) benchmarking simple longNeedle in longHaystack/lib time 100.3 ?s (100.2 ?s .. 100.5 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 100.4 ?s (100.3 ?s .. 100.9 ?s) std dev 811.3 ns (333.5 ns .. 1.575 ?s) benchmarking simple longNeedle in longHaystack/Feuer time 56.29 ?s (56.19 ?s .. 56.41 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 56.23 ?s (56.19 ?s .. 56.32 ?s) std dev 197.1 ns (116.3 ns .. 342.1 ns) benchmarking simple longNeedle in longHaystack/Abel time 94.46 ?s (94.32 ?s .. 94.66 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 94.49 ?s (94.39 ?s .. 94.70 ?s) std dev 459.8 ns (277.2 ns .. 763.7 ns) benchmarking use shortNeedle in shortHaystack/lib time 831.8 ns (828.4 ns .. 836.1 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 831.2 ns (829.3 ns .. 834.6 ns) std dev 8.468 ns (5.220 ns .. 13.26 ns) benchmarking use shortNeedle in shortHaystack/Feuer time 819.4 ns (816.7 ns .. 822.7 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 821.2 ns (818.0 ns .. 828.2 ns) std dev 15.89 ns (7.988 ns .. 25.90 ns) variance introduced by outliers: 23% (moderately inflated) benchmarking use shortNeedle in shortHaystack/Abel time 853.5 ns (851.8 ns .. 855.4 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 852.6 ns (851.5 ns .. 855.6 ns) std dev 5.462 ns (2.422 ns .. 10.51 ns) benchmarking use shortNeedle in longHaystack/lib time 261.8 ?s (259.2 ?s .. 264.7 ?s) 1.000 R? (0.999 R? .. 1.000 R?) mean 260.2 ?s (259.5 ?s .. 261.4 ?s) std dev 2.854 ?s (1.438 ?s .. 4.475 ?s) benchmarking use shortNeedle in longHaystack/Feuer time 225.0 ?s (221.9 ?s .. 227.1 ?s) 0.999 R? (0.999 R? .. 1.000 R?) mean 221.0 ?s (220.2 ?s .. 222.4 ?s) std dev 3.487 ?s (2.598 ?s .. 4.385 ?s) benchmarking use shortNeedle in longHaystack/Abel time 244.5 ?s (232.5 ?s .. 254.3 ?s) 0.992 R? (0.990 R? .. 0.997 R?) mean 232.1 ?s (229.4 ?s .. 237.7 ?s) std dev 11.45 ?s (6.248 ?s .. 16.89 ?s) variance introduced by outliers: 47% (moderately inflated) benchmarking use longNeedle in shortHaystack/lib time 1.088 ?s (1.085 ?s .. 1.091 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 1.087 ?s (1.086 ?s .. 1.090 ?s) std dev 6.936 ns (4.270 ns .. 9.691 ns) benchmarking use longNeedle in shortHaystack/Feuer time 787.4 ns (785.8 ns .. 789.9 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 786.7 ns (785.9 ns .. 788.3 ns) std dev 3.761 ns (1.408 ns .. 6.358 ns) benchmarking use longNeedle in shortHaystack/Abel time 930.7 ns (927.7 ns .. 934.0 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 928.3 ns (926.7 ns .. 931.3 ns) std dev 7.241 ns (3.785 ns .. 13.45 ns) benchmarking use longNeedle in longHaystack/lib time 262.3 ?s (257.8 ?s .. 266.1 ?s) 0.999 R? (0.999 R? .. 1.000 R?) mean 258.6 ?s (257.7 ?s .. 260.0 ?s) std dev 3.979 ?s (2.350 ?s .. 5.888 ?s) benchmarking use longNeedle in longHaystack/Feuer time 224.9 ?s (222.1 ?s .. 226.9 ?s) 0.999 R? (0.999 R? .. 1.000 R?) mean 221.2 ?s (220.4 ?s .. 222.3 ?s) std dev 3.168 ?s (2.143 ?s .. 4.010 ?s) benchmarking use longNeedle in longHaystack/Abel time 233.1 ?s (231.4 ?s .. 234.5 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 231.2 ?s (230.7 ?s .. 232.0 ?s) std dev 2.099 ?s (1.419 ?s .. 2.627 ?s) On Sun, Oct 12, 2014 at 12:02 PM, Andreas Abel wrote: > If you talk about "additional memory" you assume that after `xs isSuffix > ys`, ys is no longer needed. Is this the typical use case? > At least not in the Agda codebase, according to my quick grep... > > ./Packaging/Database.hs: > dbEntries = filter (".conf" `isSuffixOf`) filePaths > > ./TypeChecking/Monad/Open.hs: > unless (ctx `isSuffixOf` ctx') $ fail $ "thing out of context (" ++ show > ctx ++ " is not a sub context of " ++ show ctx' ++ ")" > > ./Interaction/Options.hs: > isLiterate file = ".lagda" `isSuffixOf` file > > ./Syntax/Parser.hs: > if "lagda" `isSuffixOf` filePath file then > > As I said, optimizations should be backed by benchmarks, especially when > trading a perspicuous implementation for a more complicated one... > > > On 12.10.2014 17:40, David Feuer wrote: > >> The haystack and the shared copy are only a needle's-length apart. The >> first stage traverses H and N until one of them runs out, holding a copy >> of the beginning of each. This requires at most O(min{|H|, |N|}) >> additional memory (the original needle and the needle-length prefix of >> the haystack). Assuming we didn't run out of haystack before we ran out >> of needle (which assumption seems generally likely), we proceed to the >> next step, traversing H and (drop |N| H) together. During this phase we >> hold O(|N|) additional memory: the needle itself and the needle-length >> portion of the longer of the two haystack remnants we hold. Note that in >> the second phase, we *don't* hold on to the beginning of the haystack, >> because we will never need it again! Then in the final phase, when the >> shorter haystack remnant has run out, we still have the same O(|N|) >> memory, which is now the needle itself and the needle-length suffix of >> the haystack, and (==) traverses them both together. Thus the total >> additional memory residency for this algorithm is O(min {|H|, |N|}). >> Using the length approach requires that you hold the beginning of the >> haystack for traversal while running length. To put it another way, you >> force the entire spine of the haystack to run length, and then start >> from the beginning. If the haystack is produced lazily, this potentially >> requires O(|H|) extra memory. Since you also check the length of the >> needle, your total additional memory comes to O(max {|H|, |N|}). I >> apologize if my horrid variable names obscured what goes on in the >> algorithm I described. >> >> On Sun, Oct 12, 2014 at 10:14 AM, Andreas Abel > > wrote: >> >> Well, you also traverse the haystack twice, in your getEndChunk >> function you simultaneously traverse the haystack and a (shared) >> copy of it. Why is this so much better? >> >> I guess without data (timings, heap-profiles) we do not get further >> here. >> >> On 11.10.2014 14:47, David Feuer wrote: >> >> It can be, but your way traverses the entire haystack *twice*. The >> memory needs are equivalent to the reversing version, which I >> consider >> unacceptable. >> >> >> I do not understand this comment. reverse needs O(n) memory, length >> O(1). >> >> Cheers, >> Andreas >> >> On Sat, Oct 11, 2014 at 5:57 AM, Andreas Abel > >> >> wrote: >> >> David, the essence of your idea seems mutually drop the >> correct >> number of elements from needle and hay and then compare for >> equality. Here is a concise implementation of your idea in >> terms of >> drop: >> >> isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool >> [] `isSuffixOf` _ = True >> xs `isSuffixOf` ys = xs == drop (length (drop (length xs) >> ys)) ys >> >> This can be further simplified to >> >> isSuffixOf :: forall a . (Eq a) => [a] -> [a] -> Bool >> [] `isSuffixOf` _ = True >> xs `isSuffixOf` ys = xs == drop (length ys - length xs) ys >> >> which is a very easy to understand program, I think, >> without need to >> reverse lists. >> >> >> >> _________________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/__mailman/listinfo/libraries >> >> >> >> >> -- >> Andreas Abel <>< Du bist der geliebte Mensch. >> >> Department of Computer Science and Engineering >> Chalmers and Gothenburg University, Sweden >> >> andreas.abel at gu.se >> http://www2.tcs.ifi.lmu.de/~__abel/ > abel/> >> >> >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > > -- > Andreas Abel <>< Du bist der geliebte Mensch. > > Department of Computer Science and Engineering > Chalmers and Gothenburg University, Sweden > > andreas.abel at gu.se > http://www2.tcs.ifi.lmu.de/~abel/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Mon Oct 13 19:08:19 2014 From: david.feuer at gmail.com (David Feuer) Date: Mon, 13 Oct 2014 15:08:19 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: <20141010123453.GA14905@auryn.cz> References: <20141010123453.GA14905@auryn.cz> Message-ID: I did another set of benchmarks, and Milan's implementation has a small but clear advantage over mine. Therefore I amend my proposal to use Milan's implementation instead. I would suggest perhaps using the following names: isSuffixOf :: (Eq a) => [a] -> [a] -> Bool [] `isSuffixOf` _ = True needle `isSuffixOf` hay = dropNeedleFromHay needle hay where dropNeedleFromHay [] remainingHay = dropToHayEnd remainingHay hay dropNeedleFromHay _ [] = False -- needle longer than hay dropNeedleFromHay (n:ns) (h:hs) = dropNeedleFromHay ns hs dropToHayEnd [] suffix = needle == suffix dropToHayEnd _ [] = True -- This can't happen, but returning True is measurably (slightly) faster than throwing an error here. dropToHayEnd (d:ds) (s:ss) = dropToHayEnd ds ss On Fri, Oct 10, 2014 at 8:34 AM, Milan Straka wrote: > Hi all, > > > -----Original message----- > > From: David Feuer > > Sent: 10 Oct 2014, 05:23 > > > > On Fri, Oct 10, 2014 at 5:18 AM, Jon Fairbairn < > jon.fairbairn at cl.cam.ac.uk> > > wrote: > > > > > That seems rather wordy to me. Can we get anywhere starting with > > > > > > > > It is rather wordy; I just don't know how to do better. > > What about something like the following? It uses exactly the same > algorithm, it just avoids the maybe combinator and Maybe internal > result, and renames stuff: > > isSuffixOf :: (Eq a) => [a] -> [a] -> Bool > [] `isSuffixOf` _ = True > needle `isSuffixOf` hay = subtract_and_compare needle hay > where subtract_and_compare [] diff = skip_and_compare diff hay > subtract_and_compare _ [] = False -- needle longer than hay > subtract_and_compare (n:ns) (h:hs) = subtract_and_compare ns hs > > skip_and_compare [] suffix = needle == suffix > skip_and_compare _ [] = True -- first argument must also be [] > skip_and_compare (d:ds) (s:ss) = skip_and_compare ds ss > > The redundant skip_and_compare case is there just for completeness and > readability. > > Cheers, > Milan > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From abela at chalmers.se Mon Oct 13 20:57:28 2014 From: abela at chalmers.se (Andreas Abel) Date: Mon, 13 Oct 2014 22:57:28 +0200 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> Message-ID: <543C3CB8.7060400@chalmers.se> Nice, good work! --Andreas On 13.10.2014 20:17, David Feuer wrote: > I've done the benchmarks and the results are clear: the implementation I > gave is faster than the one you gave and the one in Data.List in all > cases. Yours is usually faster than the one in Data.List, but slower for > very short lists. > > Test code: > > needles = > [ ("shortNeedle", ".exe") > ,("longNeedle", "And who by fire? Who by water? Who in the sunshine? > Who in the nighttime?")] > > haystacks = > [ ("shortHaystack", "C:\\Program Files\\Windows\\Dunno.exe") > ,("longHaystack", take 10000 $ map toEnum $ iterate (\x -> (x*131) > .&. 0xFFFF) 7)] > > impls = [("lib", L.isSuffixOf), ("Feuer", isSuffixOf), ("Abel", > isSuffixOfA)] > > tests = [("simple", (\impl (needle,haystack) -> fromEnum $ needle `impl` > haystack)), > ("use", (\impl (needle,haystack) -> > if needle `impl` haystack > then sum (map fromEnum haystack) > else product (map fromEnum haystack)))] > > main = defaultMain > [ > bgroup (unwords [fst test, fst needle, "in", fst haystack]) > [bench (fst impl) $ whnf (snd test $ snd impl) (snd needle, snd > haystack) > | impl <- impls] | test <- tests, needle <- needles, haystack <- > haystacks] > > > Results: > > benchmarking simple shortNeedle in shortHaystack/lib > time 244.6 ns (243.9 ns .. 245.6 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 245.2 ns (244.8 ns .. 246.5 ns) > std dev 2.030 ns (950.4 ps .. 4.378 ns) > > benchmarking simple shortNeedle in shortHaystack/Feuer > time 234.5 ns (234.1 ns .. 235.1 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 234.6 ns (234.2 ns .. 235.3 ns) > std dev 1.628 ns (678.1 ps .. 2.758 ns) > > benchmarking simple shortNeedle in shortHaystack/Abel > time 268.1 ns (267.8 ns .. 268.4 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 268.0 ns (267.8 ns .. 268.4 ns) > std dev 947.8 ps (538.1 ps .. 1.668 ns) > > > benchmarking simple shortNeedle in longHaystack/lib > time 100.5 ?s (100.2 ?s .. 100.9 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 100.8 ?s (100.5 ?s .. 101.4 ?s) > std dev 1.511 ?s (1.035 ?s .. 2.095 ?s) > > benchmarking simple shortNeedle in longHaystack/Feuer > time 55.66 ?s (55.61 ?s .. 55.73 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 55.68 ?s (55.63 ?s .. 55.79 ?s) > std dev 222.0 ns (128.7 ns .. 415.0 ns) > > benchmarking simple shortNeedle in longHaystack/Abel > time 94.60 ?s (94.39 ?s .. 94.94 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 94.51 ?s (94.44 ?s .. 94.68 ?s) > std dev 332.8 ns (183.6 ns .. 617.7 ns) > > > benchmarking simple longNeedle in shortHaystack/lib > time 480.6 ns (480.2 ns .. 481.1 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 480.6 ns (480.1 ns .. 481.6 ns) > std dev 2.217 ns (1.025 ns .. 4.032 ns) > > benchmarking simple longNeedle in shortHaystack/Feuer > time 187.0 ns (186.8 ns .. 187.2 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 187.0 ns (186.8 ns .. 187.4 ns) > std dev 922.0 ps (427.3 ps .. 1.598 ns) > > benchmarking simple longNeedle in shortHaystack/Abel > time 340.9 ns (339.4 ns .. 343.3 ns) > 1.000 R? (0.999 R? .. 1.000 R?) > mean 345.0 ns (341.6 ns .. 351.0 ns) > std dev 14.40 ns (9.622 ns .. 20.77 ns) > variance introduced by outliers: 60% (severely inflated) > > > benchmarking simple longNeedle in longHaystack/lib > time 100.3 ?s (100.2 ?s .. 100.5 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 100.4 ?s (100.3 ?s .. 100.9 ?s) > std dev 811.3 ns (333.5 ns .. 1.575 ?s) > > benchmarking simple longNeedle in longHaystack/Feuer > time 56.29 ?s (56.19 ?s .. 56.41 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 56.23 ?s (56.19 ?s .. 56.32 ?s) > std dev 197.1 ns (116.3 ns .. 342.1 ns) > > benchmarking simple longNeedle in longHaystack/Abel > time 94.46 ?s (94.32 ?s .. 94.66 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 94.49 ?s (94.39 ?s .. 94.70 ?s) > std dev 459.8 ns (277.2 ns .. 763.7 ns) > > > benchmarking use shortNeedle in shortHaystack/lib > time 831.8 ns (828.4 ns .. 836.1 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 831.2 ns (829.3 ns .. 834.6 ns) > std dev 8.468 ns (5.220 ns .. 13.26 ns) > > benchmarking use shortNeedle in shortHaystack/Feuer > time 819.4 ns (816.7 ns .. 822.7 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 821.2 ns (818.0 ns .. 828.2 ns) > std dev 15.89 ns (7.988 ns .. 25.90 ns) > variance introduced by outliers: 23% (moderately inflated) > > benchmarking use shortNeedle in shortHaystack/Abel > time 853.5 ns (851.8 ns .. 855.4 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 852.6 ns (851.5 ns .. 855.6 ns) > std dev 5.462 ns (2.422 ns .. 10.51 ns) > > > benchmarking use shortNeedle in longHaystack/lib > time 261.8 ?s (259.2 ?s .. 264.7 ?s) > 1.000 R? (0.999 R? .. 1.000 R?) > mean 260.2 ?s (259.5 ?s .. 261.4 ?s) > std dev 2.854 ?s (1.438 ?s .. 4.475 ?s) > > benchmarking use shortNeedle in longHaystack/Feuer > time 225.0 ?s (221.9 ?s .. 227.1 ?s) > 0.999 R? (0.999 R? .. 1.000 R?) > mean 221.0 ?s (220.2 ?s .. 222.4 ?s) > std dev 3.487 ?s (2.598 ?s .. 4.385 ?s) > > benchmarking use shortNeedle in longHaystack/Abel > time 244.5 ?s (232.5 ?s .. 254.3 ?s) > 0.992 R? (0.990 R? .. 0.997 R?) > mean 232.1 ?s (229.4 ?s .. 237.7 ?s) > std dev 11.45 ?s (6.248 ?s .. 16.89 ?s) > variance introduced by outliers: 47% (moderately inflated) > > > benchmarking use longNeedle in shortHaystack/lib > time 1.088 ?s (1.085 ?s .. 1.091 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 1.087 ?s (1.086 ?s .. 1.090 ?s) > std dev 6.936 ns (4.270 ns .. 9.691 ns) > > benchmarking use longNeedle in shortHaystack/Feuer > time 787.4 ns (785.8 ns .. 789.9 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 786.7 ns (785.9 ns .. 788.3 ns) > std dev 3.761 ns (1.408 ns .. 6.358 ns) > > benchmarking use longNeedle in shortHaystack/Abel > time 930.7 ns (927.7 ns .. 934.0 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 928.3 ns (926.7 ns .. 931.3 ns) > std dev 7.241 ns (3.785 ns .. 13.45 ns) > > > benchmarking use longNeedle in longHaystack/lib > time 262.3 ?s (257.8 ?s .. 266.1 ?s) > 0.999 R? (0.999 R? .. 1.000 R?) > mean 258.6 ?s (257.7 ?s .. 260.0 ?s) > std dev 3.979 ?s (2.350 ?s .. 5.888 ?s) > > benchmarking use longNeedle in longHaystack/Feuer > time 224.9 ?s (222.1 ?s .. 226.9 ?s) > 0.999 R? (0.999 R? .. 1.000 R?) > mean 221.2 ?s (220.4 ?s .. 222.3 ?s) > std dev 3.168 ?s (2.143 ?s .. 4.010 ?s) > > benchmarking use longNeedle in longHaystack/Abel > time 233.1 ?s (231.4 ?s .. 234.5 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 231.2 ?s (230.7 ?s .. 232.0 ?s) > std dev 2.099 ?s (1.419 ?s .. 2.627 ?s) > > On Sun, Oct 12, 2014 at 12:02 PM, Andreas Abel > wrote: > > If you talk about "additional memory" you assume that after `xs > isSuffix ys`, ys is no longer needed. Is this the typical use case? > At least not in the Agda codebase, according to my quick grep... > > ./Packaging/Database.hs: > dbEntries = filter (".conf" `isSuffixOf`) filePaths > > ./TypeChecking/Monad/Open.hs: > unless (ctx `isSuffixOf` ctx') $ fail $ "thing out of context (" > ++ show ctx ++ " is not a sub context of " ++ show ctx' ++ ")" > > ./Interaction/Options.hs: > isLiterate file = ".lagda" `isSuffixOf` file > > ./Syntax/Parser.hs: > if "lagda" `isSuffixOf` filePath file then > > As I said, optimizations should be backed by benchmarks, especially > when trading a perspicuous implementation for a more complicated one... > > > On 12.10.2014 17:40, David Feuer wrote: > > The haystack and the shared copy are only a needle's-length > apart. The > first stage traverses H and N until one of them runs out, > holding a copy > of the beginning of each. This requires at most O(min{|H|, |N|}) > additional memory (the original needle and the needle-length > prefix of > the haystack). Assuming we didn't run out of haystack before we > ran out > of needle (which assumption seems generally likely), we proceed > to the > next step, traversing H and (drop |N| H) together. During this > phase we > hold O(|N|) additional memory: the needle itself and the > needle-length > portion of the longer of the two haystack remnants we hold. Note > that in > the second phase, we *don't* hold on to the beginning of the > haystack, > because we will never need it again! Then in the final phase, > when the > shorter haystack remnant has run out, we still have the same O(|N|) > memory, which is now the needle itself and the needle-length > suffix of > the haystack, and (==) traverses them both together. Thus the total > additional memory residency for this algorithm is O(min {|H|, |N|}). > Using the length approach requires that you hold the beginning > of the > haystack for traversal while running length. To put it another > way, you > force the entire spine of the haystack to run length, and then start > from the beginning. If the haystack is produced lazily, this > potentially > requires O(|H|) extra memory. Since you also check the length of the > needle, your total additional memory comes to O(max {|H|, |N|}). I > apologize if my horrid variable names obscured what goes on in the > algorithm I described. > > On Sun, Oct 12, 2014 at 10:14 AM, Andreas Abel > > >> wrote: > > Well, you also traverse the haystack twice, in your getEndChunk > function you simultaneously traverse the haystack and a > (shared) > copy of it. Why is this so much better? > > I guess without data (timings, heap-profiles) we do not get > further > here. > > On 11.10.2014 14:47, David Feuer wrote: > > It can be, but your way traverses the entire haystack > *twice*. The > memory needs are equivalent to the reversing version, > which I > consider > unacceptable. > > > I do not understand this comment. reverse needs O(n) > memory, length > O(1). > > Cheers, > Andreas > > On Sat, Oct 11, 2014 at 5:57 AM, Andreas Abel wrote: > > David, the essence of your idea seems mutually > drop the correct > number of elements from needle and hay and then > compare for > equality. Here is a concise implementation of > your idea in > terms of > drop: > > isSuffixOf :: forall a . (Eq a) => [a] -> > [a] -> Bool > [] `isSuffixOf` _ = True > xs `isSuffixOf` ys = xs == drop (length (drop > (length xs) > ys)) ys > > This can be further simplified to > > isSuffixOf :: forall a . (Eq a) => [a] -> > [a] -> Bool > [] `isSuffixOf` _ = True > xs `isSuffixOf` ys = xs == drop (length ys - > length xs) ys > > which is a very easy to understand program, I think, > without need to > reverse lists. > -- 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 ky3 at atamo.com Mon Oct 13 22:10:18 2014 From: ky3 at atamo.com (Kim-Ee Yeoh) Date: Tue, 14 Oct 2014 05:10:18 +0700 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> Message-ID: On Tue, Oct 14, 2014 at 1:17 AM, David Feuer wrote: > I've done the benchmarks and the results are clear: the implementation I > gave is faster than the one you gave and the one in Data.List in all cases. > Yours is usually faster than the one in Data.List, but slower for very > short lists. The 2x factor you're seeing over Andreas's diminishes once we put slightly more effort into an apples-to-apples comparison. 1. Instead of drop (length xs) ys, let's define the equivalent dropl :: [b] -> [a] -> [a] dropl (_:xs) (_:ys) = dropl xs ys dropl [] ys = ys dropl xs [] = [] i.e. dropl xs ys ~ drop (length xs) ys. Now with Andreas's original version: xs `isSuffixOfA` ys = xs == dropl (dropl xs ys) ys that 2x gap narrows down to 10% for most cases. 2. There's that fast path which you optimize for, where the needle is patently too long to be in the haystack. To narrow the semantic gap, we can write dropm :: [b] -> [a] -> Maybe [a] dropm (_:xs) (_:ys) = dropm xs ys dropm [] ys = Just ys dropm _ [] = Nothing xs `isSuffixOfA` ys = maybe False id $ do zs <- dropm xs ys ws <- dropm zs ys -- ws = needle-sized slice of the end of haystack return $ xs == ws Now, the long-needle-short-haystack case also becomes merely 10% off. I'm -1 on both your proposal and the no.2 code because it's too much verbosity for uncertain gain. The benchmarks look good, but is the function even the bottleneck? For folks that care deeply about speed, lists is almost always the wrong datatype anyway. I'm weakly +1 on no.1 because it beats the current double reverse definition! -- Kim-Ee -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Mon Oct 13 23:02:40 2014 From: david.feuer at gmail.com (David Feuer) Date: Mon, 13 Oct 2014 19:02:40 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> Message-ID: I've switched my allegiance from my own version to Milan's, because it's a tad faster, and also less verbose. One thing to watch out for: although I don't particularly like this, the current version in Data.List makes [] `isSuffixOf` undefined = True. Unless there's a general consensus that this doesn't matter, we need to preserve it. I don't think Milan's version is too terribly verbose. I tested something very similar to your #1 that was proposed on IRC by Reid Barton, and the numbers just didn't look too wonderful. I don't think Milan's version is too terribly verbose, and I think it's clearer than your #2. As for the depth of caring about speed, I generally disagree with you: lists are actually very good for some purposes, and, moreover, even when they're *not*, people use them anyway and then other people wait for that code to run. On Mon, Oct 13, 2014 at 6:10 PM, Kim-Ee Yeoh wrote: > > On Tue, Oct 14, 2014 at 1:17 AM, David Feuer > wrote: > >> I've done the benchmarks and the results are clear: the implementation I >> gave is faster than the one you gave and the one in Data.List in all cases. >> Yours is usually faster than the one in Data.List, but slower for very >> short lists. > > > The 2x factor you're seeing over Andreas's diminishes once we put slightly > more effort into an apples-to-apples comparison. > > 1. Instead of drop (length xs) ys, let's define the equivalent > > dropl :: [b] -> [a] -> [a] > dropl (_:xs) (_:ys) = dropl xs ys > dropl [] ys = ys > dropl xs [] = [] > > i.e. dropl xs ys ~ drop (length xs) ys. > > Now with Andreas's original version: > > xs `isSuffixOfA` ys = xs == dropl (dropl xs ys) ys > > that 2x gap narrows down to 10% for most cases. > > 2. There's that fast path which you optimize for, where the needle is > patently too long to be in the haystack. To narrow the semantic gap, we can > write > > dropm :: [b] -> [a] -> Maybe [a] > dropm (_:xs) (_:ys) = dropm xs ys > dropm [] ys = Just ys > dropm _ [] = Nothing > > xs `isSuffixOfA` ys = maybe False id $ do > zs <- dropm xs ys > ws <- dropm zs ys -- ws = needle-sized slice of the end of haystack > return $ xs == ws > > Now, the long-needle-short-haystack case also becomes merely 10% off. > > I'm -1 on both your proposal and the no.2 code because it's too much > verbosity for uncertain gain. The benchmarks look good, but is the function > even the bottleneck? For folks that care deeply about speed, lists is > almost always the wrong datatype anyway. > > I'm weakly +1 on no.1 because it beats the current double reverse > definition! > > -- Kim-Ee > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ky3 at atamo.com Tue Oct 14 13:05:14 2014 From: ky3 at atamo.com (Kim-Ee Yeoh) Date: Tue, 14 Oct 2014 20:05:14 +0700 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> Message-ID: David, To paraphrase Kernighan, ascertaining correctness is twice as hard as writing a program in the first place. So if you're as clever as possible with your code, how will you know it's even correct? Case in point: the infinite lists wrinkle that you started the thread with. /At a glance/ what do the general recursion versions (yours and Milan's) evaluate to on infinite lists? What are the benchmarks on the time it takes for a haskell programmer to figure them out? Would they not jump at the greater affordance of reasoning with Andreas's compositions? Meaning and reasonableness have always been the hallmarks of core libs. Least of all, since it's so losering to benchmark the wrong thing, see below on how Andreas-dropl no.1 beats out David-Milan by the tiniest sliver in short-needle-long-haystack. Like checking file extensions in pathnames that we saw in Andreas's Agda code. Here a concrete app brings real meaning to the timings as opposed to optimizing for vaporware. Watch them Agdaists fall off their chairs when they hit the speed boost. Don't mean to preach to the choir. Only layin' down the facts for the sake of the archive that every boiled haskeller knows to switch datatypes if isSuffixOf becomes the bottleneck. benchmarking simple shortNeedle in shortHaystack/lib time 176.6 ns (176.4 ns .. 177.0 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 176.6 ns (176.5 ns .. 176.9 ns) std dev 596.3 ps (318.4 ps .. 1.096 ns) benchmarking simple shortNeedle in shortHaystack/Milan time 135.6 ns (135.6 ns .. 135.6 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 135.6 ns (135.6 ns .. 135.6 ns) std dev 45.49 ps (23.88 ps .. 79.14 ps) benchmarking simple shortNeedle in shortHaystack/Abel time 145.6 ns (142.5 ns .. 149.5 ns) 0.996 R? (0.996 R? .. 0.997 R?) mean 147.3 ns (144.8 ns .. 150.0 ns) std dev 8.616 ns (8.070 ns .. 9.037 ns) variance introduced by outliers: 76% (severely inflated) benchmarking simple shortNeedle in longHaystack/lib time 71.12 ?s (71.08 ?s .. 71.15 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 71.12 ?s (71.08 ?s .. 71.16 ?s) std dev 142.7 ns (115.6 ns .. 186.3 ns) benchmarking simple shortNeedle in longHaystack/Milan time 45.00 ?s (44.99 ?s .. 45.00 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 45.00 ?s (45.00 ?s .. 45.01 ?s) std dev 21.04 ns (15.62 ns .. 28.75 ns) benchmarking simple shortNeedle in longHaystack/Abel time 43.68 ?s (43.68 ?s .. 43.70 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 43.69 ?s (43.68 ?s .. 43.69 ?s) std dev 18.29 ns (12.79 ns .. 27.76 ns) benchmarking simple longNeedle in shortHaystack/lib time 396.3 ns (396.2 ns .. 396.6 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 396.6 ns (396.3 ns .. 397.0 ns) std dev 1.106 ns (707.9 ps .. 1.662 ns) benchmarking simple longNeedle in shortHaystack/Milan time 117.9 ns (117.9 ns .. 118.0 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 117.9 ns (117.9 ns .. 117.9 ns) std dev 49.08 ps (30.66 ps .. 75.20 ps) benchmarking simple longNeedle in shortHaystack/Abel time 125.6 ns (125.6 ns .. 125.6 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 125.6 ns (125.6 ns .. 125.6 ns) std dev 35.17 ps (19.08 ps .. 58.78 ps) benchmarking simple longNeedle in longHaystack/lib time 71.98 ?s (71.92 ?s .. 72.03 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 71.93 ?s (71.85 ?s .. 72.00 ?s) std dev 247.4 ns (199.9 ns .. 305.3 ns) benchmarking simple longNeedle in longHaystack/Milan time 47.26 ?s (47.24 ?s .. 47.29 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 47.28 ?s (47.27 ?s .. 47.29 ?s) std dev 35.43 ns (28.70 ns .. 45.80 ns) benchmarking simple longNeedle in longHaystack/Abel time 47.44 ?s (47.43 ?s .. 47.45 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 47.44 ?s (47.44 ?s .. 47.45 ?s) std dev 16.81 ns (10.63 ns .. 28.75 ns) benchmarking use shortNeedle in shortHaystack/lib time 617.9 ns (616.8 ns .. 618.7 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 617.9 ns (616.9 ns .. 618.4 ns) std dev 2.295 ns (977.3 ps .. 3.747 ns) benchmarking use shortNeedle in shortHaystack/Milan time 570.7 ns (570.6 ns .. 570.8 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 570.7 ns (570.6 ns .. 570.7 ns) std dev 194.8 ps (154.1 ps .. 262.9 ps) benchmarking use shortNeedle in shortHaystack/Abel time 576.8 ns (575.5 ns .. 579.5 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 576.5 ns (575.7 ns .. 578.9 ns) std dev 5.133 ns (149.4 ps .. 9.882 ns) benchmarking use shortNeedle in longHaystack/lib time 194.4 ?s (192.0 ?s .. 195.9 ?s) 0.999 R? (0.999 R? .. 1.000 R?) mean 190.9 ?s (190.2 ?s .. 191.9 ?s) std dev 2.789 ?s (1.938 ?s .. 3.452 ?s) benchmarking use shortNeedle in longHaystack/Milan time 169.3 ?s (164.6 ?s .. 171.8 ?s) 0.997 R? (0.996 R? .. 0.998 R?) mean 160.1 ?s (158.1 ?s .. 162.6 ?s) std dev 7.419 ?s (5.720 ?s .. 8.512 ?s) variance introduced by outliers: 46% (moderately inflated) benchmarking use shortNeedle in longHaystack/Abel time 166.4 ?s (162.9 ?s .. 168.4 ?s) 0.998 R? (0.997 R? .. 0.999 R?) mean 159.1 ?s (157.5 ?s .. 161.0 ?s) std dev 5.903 ?s (4.471 ?s .. 6.721 ?s) variance introduced by outliers: 35% (moderately inflated) benchmarking use longNeedle in shortHaystack/lib time 828.0 ns (827.8 ns .. 828.2 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 828.0 ns (827.9 ns .. 828.2 ns) std dev 582.1 ps (339.9 ps .. 970.5 ps) benchmarking use longNeedle in shortHaystack/Milan time 550.0 ns (550.0 ns .. 550.1 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 550.0 ns (550.0 ns .. 550.1 ns) std dev 223.1 ps (97.52 ps .. 438.8 ps) benchmarking use longNeedle in shortHaystack/Abel time 562.1 ns (562.1 ns .. 562.2 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 562.1 ns (562.1 ns .. 562.2 ns) std dev 109.5 ps (74.48 ps .. 182.3 ps) benchmarking use longNeedle in longHaystack/lib time 195.7 ?s (193.3 ?s .. 197.3 ?s) 0.999 R? (0.999 R? .. 1.000 R?) mean 191.9 ?s (191.1 ?s .. 193.0 ?s) std dev 3.065 ?s (2.169 ?s .. 3.825 ?s) benchmarking use longNeedle in longHaystack/Milan time 170.6 ?s (165.7 ?s .. 173.4 ?s) 0.996 R? (0.995 R? .. 0.998 R?) mean 160.8 ?s (158.6 ?s .. 163.5 ?s) std dev 7.928 ?s (6.085 ?s .. 9.063 ?s) variance introduced by outliers: 49% (moderately inflated) benchmarking use longNeedle in longHaystack/Abel time 170.4 ?s (165.4 ?s .. 173.2 ?s) 0.996 R? (0.995 R? .. 0.997 R?) mean 160.5 ?s (158.3 ?s .. 163.3 ?s) std dev 8.066 ?s (6.200 ?s .. 9.280 ?s) variance introduced by outliers: 50% (moderately inflated) This is 64-bit on a recent i5. I appreciate learning something new from this discussion, so to pay it forward please find attached a self-contained lhs for your nano-tweaking pleasure. -- Kim-Ee On Tue, Oct 14, 2014 at 6:02 AM, David Feuer wrote: > I've switched my allegiance from my own version to Milan's, because it's a > tad faster, and also less verbose. One thing to watch out for: although I > don't particularly like this, the current version in Data.List makes [] > `isSuffixOf` undefined = True. Unless there's a general consensus that > this doesn't matter, we need to preserve it. > > I don't think Milan's version is too terribly verbose. I tested something > very similar to your #1 that was proposed on IRC by Reid Barton, and the > numbers just didn't look too wonderful. I don't think Milan's version is > too terribly verbose, and I think it's clearer than your #2. As for the > depth of caring about speed, I generally disagree with you: lists are > actually very good for some purposes, and, moreover, even when they're > *not*, people use them anyway and then other people wait for that code to > run. > > On Mon, Oct 13, 2014 at 6:10 PM, Kim-Ee Yeoh wrote: > >> >> On Tue, Oct 14, 2014 at 1:17 AM, David Feuer >> wrote: >> >>> I've done the benchmarks and the results are clear: the implementation I >>> gave is faster than the one you gave and the one in Data.List in all cases. >>> Yours is usually faster than the one in Data.List, but slower for very >>> short lists. >> >> >> The 2x factor you're seeing over Andreas's diminishes once we put >> slightly more effort into an apples-to-apples comparison. >> >> 1. Instead of drop (length xs) ys, let's define the equivalent >> >> dropl :: [b] -> [a] -> [a] >> dropl (_:xs) (_:ys) = dropl xs ys >> dropl [] ys = ys >> dropl xs [] = [] >> >> i.e. dropl xs ys ~ drop (length xs) ys. >> >> Now with Andreas's original version: >> >> xs `isSuffixOfA` ys = xs == dropl (dropl xs ys) ys >> >> that 2x gap narrows down to 10% for most cases. >> >> 2. There's that fast path which you optimize for, where the needle is >> patently too long to be in the haystack. To narrow the semantic gap, we can >> write >> >> dropm :: [b] -> [a] -> Maybe [a] >> dropm (_:xs) (_:ys) = dropm xs ys >> dropm [] ys = Just ys >> dropm _ [] = Nothing >> >> xs `isSuffixOfA` ys = maybe False id $ do >> zs <- dropm xs ys >> ws <- dropm zs ys -- ws = needle-sized slice of the end of haystack >> return $ xs == ws >> >> Now, the long-needle-short-haystack case also becomes merely 10% off. >> >> I'm -1 on both your proposal and the no.2 code because it's too much >> verbosity for uncertain gain. The benchmarks look good, but is the function >> even the bottleneck? For folks that care deeply about speed, lists is >> almost always the wrong datatype anyway. >> >> I'm weakly +1 on no.1 because it beats the current double reverse >> definition! >> >> -- Kim-Ee >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: T_isSuffixOf.lhs Type: text/x-literate-haskell Size: 2150 bytes Desc: not available URL: From hvr at gnu.org Tue Oct 14 16:00:19 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Tue, 14 Oct 2014 18:00:19 +0200 Subject: Proposal: Add isSubsequenceOf to Data.List In-Reply-To: <543BF0F9.9050905@nh2.me> ("Niklas \=\?utf-8\?Q\?Hamb\=C3\=BCchen\?\= \=\?utf-8\?Q\?\=22's\?\= message of "Mon, 13 Oct 2014 17:34:17 +0200") References: <543BF0F9.9050905@nh2.me> Message-ID: <878uki8wvg.fsf@gnu.org> On 2014-10-13 at 17:34:17 +0200, Niklas Hamb?chen wrote: [...] > With this proposal, we would add > > * isSubsequenceOf (dual of subsequences) > > > Suggested implementation: > > -- | `isSubsequenceOf a b`: Checks if a is a subsequence of b. > isSubsequenceOf :: (Eq a) => [a] -> [a] -> Bool > isSubsequenceOf [] _ = True > isSubsequenceOf _ [] = False > isSubsequenceOf a@(x:a') (y:b) | x == y = isSubsequenceOf a' b > | otherwise = isSubsequenceOf a b +1 From mail at joachim-breitner.de Tue Oct 14 19:15:14 2014 From: mail at joachim-breitner.de (Joachim Breitner) Date: Tue, 14 Oct 2014 21:15:14 +0200 Subject: Proposal: Add isSubsequenceOf to Data.List In-Reply-To: <543BF0F9.9050905@nh2.me> References: <543BF0F9.9050905@nh2.me> Message-ID: <1413314114.1381.6.camel@joachim-breitner.de> Hi, Am Montag, den 13.10.2014, 17:34 +0200 schrieb Niklas Hamb?chen: > `isSubsequenceOf` would go into the "Predicates" section > (http://hackage.haskell.org/package/base-4.7.0.1/docs/Data-List.html#g:12) > which already contains: > > * isPrefixOf (dual of inits) > * isSuffixOf (dual of tails) > * isInfixOf > > With this proposal, we would add > > * isSubsequenceOf (dual of subsequences) +1 > Suggested implementation: > > -- | `isSubsequenceOf a b`: Checks if a is a subsequence of b. > isSubsequenceOf :: (Eq a) => [a] -> [a] -> Bool > isSubsequenceOf [] _ = True > isSubsequenceOf _ [] = False > isSubsequenceOf a@(x:a') (y:b) | x == y = isSubsequenceOf a' b > | otherwise = isSubsequenceOf a b The docs should explain what a subsequence is (possibly by giving an educating example, or referring to "subsequences"). 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 ky3 at atamo.com Tue Oct 14 19:27:14 2014 From: ky3 at atamo.com (Kim-Ee Yeoh) Date: Wed, 15 Oct 2014 02:27:14 +0700 Subject: Proposal: Add isSubsequenceOf to Data.List In-Reply-To: <543BF0F9.9050905@nh2.me> References: <543BF0F9.9050905@nh2.me> Message-ID: On Mon, Oct 13, 2014 at 10:34 PM, Niklas Hamb?chen wrote: > * isSubsequenceOf (dual of subsequences) +1 Suggested haddock to assist usage: Every infix of str is also a subsequence of str, but the converse doesn't generally hold. E.g. "ac" `isSubsequenceOf` "abc" is True, but "ac" `isInfixOf` "abc" is False. As negative examples, neither "ba" nor "bca" isSubsequenceOf "abc". -- Kim-Ee -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Tue Oct 14 20:04:17 2014 From: david.feuer at gmail.com (David Feuer) Date: Tue, 14 Oct 2014 16:04:17 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: Message-ID: On Oct 14, 2014 9:05 AM, "Kim-Ee Yeoh" wrote: > > David, > > To paraphrase Kernighan, ascertaining correctness is twice as hard as writing a program in the first place. So if you're as clever as possible with your code, how will you know it's even correct? I think we have different senses of what is easy to understand. We're all working on modifications of Andreas Abel's "naive" approach. I don't think the Reid Barton/Kim-Ee Yeoh modification is easier to understand than the David Feuer/Milan Straka one. In particular, your approach makes the weird long needle/short haystack case implicit, dumping it into the equality test. I also think the principle of least (bad) surprise applies: I wouldn't *expect* an overly long needle to be traversed in full and then the elements compared. > Case in point: the infinite lists wrinkle that you started the thread with. /At a glance/ what do the general recursion versions (yours and Milan's) evaluate to on infinite lists? I can't undo my understanding and say what I would have thought. But it's certainly a whole lot easier to understand than, say, the `permutations` or `sort` functions, and I could easily add two or three lines of explanation that would guide anyone to a correct interpretation. > What are the benchmarks on the time it takes for a haskell programmer to figure them out? Would they not jump at the greater affordance of reasoning with Andreas's compositions? Let me know when the benchmarks and experimental results are in. Don't forget to get IRB approval for human trials. > Meaning and reasonableness have always been the hallmarks of core libs. I think we have an honest disagreement hear about what is "reasonable". I think it's unreasonable for [undefined, undefined] `isSuffixOf` [undefined] to be undefined, but you see it differently. > Least of all, since it's so losering to benchmark the wrong thing, see below on how Andreas-dropl no.1 beats out David-Milan by the tiniest sliver in short-needle-long-haystack. Like checking file extensions in pathnames that we saw in Andreas's Agda code. The "long haystack" benchmark I used is actually much, much longer than a path name. My "short needle, short haystack" example is the one designed to test the pathname extension performance. > Here a concrete app brings real meaning to the timings as opposed to optimizing for vaporware. Watch them Agdaists fall off their chairs when they hit the speed boost. ;) -------------- next part -------------- An HTML attachment was scrubbed... URL: From andreas.abel at ifi.lmu.de Tue Oct 14 21:24:36 2014 From: andreas.abel at ifi.lmu.de (Andreas Abel) Date: Tue, 14 Oct 2014 23:24:36 +0200 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> Message-ID: <543D9494.2040309@ifi.lmu.de> It would be interesting to compare the correctness arguments for the different versions of isSuffixOf. I gave the dropl-version a try in Agda, but it is not trivial, I could not finish in 90 min. Here is a start: open import Data.List open import Data.Product open import Relation.Binary.PropositionalEquality as ? postulate append-[] : ?{A : Set} {xs : List A} ? xs ++ [] ? xs cong-tail : ?{A : Set} {x y : A} {xs ys} ? x ? xs ? y ? ys ? xs ? ys dropL : ?{A B : Set} ? List A ? List B ? List B dropL [] ys = ys dropL xs [] = [] dropL (x ? xs) (y ? ys) = dropL xs ys dropL-is-drop-length : ?{A B : Set} (xs : List A) (ys : List B) ? dropL xs ys ? drop (length xs) ys dropL-is-drop-length [] ys = refl dropL-is-drop-length (x ? xs) [] = refl dropL-is-drop-length (x ? xs) (y ? ys) = dropL-is-drop-length xs ys -- Logical definition of suffix: _IsSuffixOf_ : ?{A} ? List A ? List A ? Set ys IsSuffixOf zs = ? ? xs ? xs ++ ys ? zs dropL-suffix : ?{A B : Set} (xs : List A) (ys : List B) ? dropL xs ys IsSuffixOf ys dropL-suffix [] ys = [] , refl dropL-suffix (x ? xs) [] = [] , refl dropL-suffix (x ? xs) (y ? ys) with dropL-suffix xs ys ... | ws , p = (y ? ws) , cong (? zs ? y ? zs) p -- This is one direction, rather easy: dropL-dropL-suffix : ?{A : Set} (xs ys : List A) ? dropL (dropL xs ys) ys ? xs ? xs IsSuffixOf ys dropL-dropL-suffix xs ys p = subst (? ws ? ws IsSuffixOf ys) p (dropL-suffix (dropL xs ys) ys) -- One more easy lemma: dropL-diag : ?{A : Set} (xs : List A) ? dropL xs xs ? [] dropL-diag [] = refl dropL-diag (x ? xs) = dropL-diag xs -- The other direction, hard: suffix-dropL-dropL : ?{A : Set} (xs ys : List A) ? xs IsSuffixOf ys ? dropL (dropL xs ys) ys ? xs suffix-dropL-dropL xs .xs ([] , refl) rewrite dropL-diag xs = refl suffix-dropL-dropL xs [] (w ? ws , ()) suffix-dropL-dropL [] (y ? ys) (w ? ws , p) = dropL-diag ys suffix-dropL-dropL (x ? xs) (y ? ys) (w ? ws , p) = {!suffix-dropL-dropL (x ? xs) ys (ws , cong-tail p)!} -- stuck here. On 14.10.2014 15:05, Kim-Ee Yeoh wrote: > David, > > To paraphrase Kernighan, ascertaining correctness is twice as hard as > writing a program in the first place. So if you're as clever as possible > with your code, how will you know it's even correct? > > Case in point: the infinite lists wrinkle that you started the thread > with. /At a glance/ what do the general recursion versions (yours and > Milan's) evaluate to on infinite lists? What are the benchmarks on the > time it takes for a haskell programmer to figure them out? Would they > not jump at the greater affordance of reasoning with Andreas's compositions? > > Meaning and reasonableness have always been the hallmarks of core libs. > > Least of all, since it's so losering to benchmark the wrong thing, see > below on how Andreas-dropl no.1 beats out David-Milan by the tiniest > sliver in short-needle-long-haystack. Like checking file extensions in > pathnames that we saw in Andreas's Agda code. Here a concrete app brings > real meaning to the timings as opposed to optimizing for vaporware. > Watch them Agdaists fall off their chairs when they hit the speed boost. > > Don't mean to preach to the choir. Only layin' down the facts for the > sake of the archive that every boiled haskeller knows to switch > datatypes if isSuffixOf becomes the bottleneck. > > benchmarking simple shortNeedle in shortHaystack/lib > time 176.6 ns (176.4 ns .. 177.0 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 176.6 ns (176.5 ns .. 176.9 ns) > std dev 596.3 ps (318.4 ps .. 1.096 ns) > > benchmarking simple shortNeedle in shortHaystack/Milan > time 135.6 ns (135.6 ns .. 135.6 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 135.6 ns (135.6 ns .. 135.6 ns) > std dev 45.49 ps (23.88 ps .. 79.14 ps) > > benchmarking simple shortNeedle in shortHaystack/Abel > time 145.6 ns (142.5 ns .. 149.5 ns) > 0.996 R? (0.996 R? .. 0.997 R?) > mean 147.3 ns (144.8 ns .. 150.0 ns) > std dev 8.616 ns (8.070 ns .. 9.037 ns) > variance introduced by outliers: 76% (severely inflated) > > benchmarking simple shortNeedle in longHaystack/lib > time 71.12 ?s (71.08 ?s .. 71.15 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 71.12 ?s (71.08 ?s .. 71.16 ?s) > std dev 142.7 ns (115.6 ns .. 186.3 ns) > > benchmarking simple shortNeedle in longHaystack/Milan > time 45.00 ?s (44.99 ?s .. 45.00 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 45.00 ?s (45.00 ?s .. 45.01 ?s) > std dev 21.04 ns (15.62 ns .. 28.75 ns) > > benchmarking simple shortNeedle in longHaystack/Abel > time 43.68 ?s (43.68 ?s .. 43.70 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 43.69 ?s (43.68 ?s .. 43.69 ?s) > std dev 18.29 ns (12.79 ns .. 27.76 ns) > > benchmarking simple longNeedle in shortHaystack/lib > time 396.3 ns (396.2 ns .. 396.6 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 396.6 ns (396.3 ns .. 397.0 ns) > std dev 1.106 ns (707.9 ps .. 1.662 ns) > > benchmarking simple longNeedle in shortHaystack/Milan > time 117.9 ns (117.9 ns .. 118.0 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 117.9 ns (117.9 ns .. 117.9 ns) > std dev 49.08 ps (30.66 ps .. 75.20 ps) > > benchmarking simple longNeedle in shortHaystack/Abel > time 125.6 ns (125.6 ns .. 125.6 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 125.6 ns (125.6 ns .. 125.6 ns) > std dev 35.17 ps (19.08 ps .. 58.78 ps) > > benchmarking simple longNeedle in longHaystack/lib > time 71.98 ?s (71.92 ?s .. 72.03 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 71.93 ?s (71.85 ?s .. 72.00 ?s) > std dev 247.4 ns (199.9 ns .. 305.3 ns) > > benchmarking simple longNeedle in longHaystack/Milan > time 47.26 ?s (47.24 ?s .. 47.29 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 47.28 ?s (47.27 ?s .. 47.29 ?s) > std dev 35.43 ns (28.70 ns .. 45.80 ns) > > benchmarking simple longNeedle in longHaystack/Abel > time 47.44 ?s (47.43 ?s .. 47.45 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 47.44 ?s (47.44 ?s .. 47.45 ?s) > std dev 16.81 ns (10.63 ns .. 28.75 ns) > > benchmarking use shortNeedle in shortHaystack/lib > time 617.9 ns (616.8 ns .. 618.7 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 617.9 ns (616.9 ns .. 618.4 ns) > std dev 2.295 ns (977.3 ps .. 3.747 ns) > > benchmarking use shortNeedle in shortHaystack/Milan > time 570.7 ns (570.6 ns .. 570.8 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 570.7 ns (570.6 ns .. 570.7 ns) > std dev 194.8 ps (154.1 ps .. 262.9 ps) > > benchmarking use shortNeedle in shortHaystack/Abel > time 576.8 ns (575.5 ns .. 579.5 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 576.5 ns (575.7 ns .. 578.9 ns) > std dev 5.133 ns (149.4 ps .. 9.882 ns) > > benchmarking use shortNeedle in longHaystack/lib > time 194.4 ?s (192.0 ?s .. 195.9 ?s) > 0.999 R? (0.999 R? .. 1.000 R?) > mean 190.9 ?s (190.2 ?s .. 191.9 ?s) > std dev 2.789 ?s (1.938 ?s .. 3.452 ?s) > > benchmarking use shortNeedle in longHaystack/Milan > time 169.3 ?s (164.6 ?s .. 171.8 ?s) > 0.997 R? (0.996 R? .. 0.998 R?) > mean 160.1 ?s (158.1 ?s .. 162.6 ?s) > std dev 7.419 ?s (5.720 ?s .. 8.512 ?s) > variance introduced by outliers: 46% (moderately inflated) > > benchmarking use shortNeedle in longHaystack/Abel > time 166.4 ?s (162.9 ?s .. 168.4 ?s) > 0.998 R? (0.997 R? .. 0.999 R?) > mean 159.1 ?s (157.5 ?s .. 161.0 ?s) > std dev 5.903 ?s (4.471 ?s .. 6.721 ?s) > variance introduced by outliers: 35% (moderately inflated) > > benchmarking use longNeedle in shortHaystack/lib > time 828.0 ns (827.8 ns .. 828.2 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 828.0 ns (827.9 ns .. 828.2 ns) > std dev 582.1 ps (339.9 ps .. 970.5 ps) > > benchmarking use longNeedle in shortHaystack/Milan > time 550.0 ns (550.0 ns .. 550.1 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 550.0 ns (550.0 ns .. 550.1 ns) > std dev 223.1 ps (97.52 ps .. 438.8 ps) > > benchmarking use longNeedle in shortHaystack/Abel > time 562.1 ns (562.1 ns .. 562.2 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 562.1 ns (562.1 ns .. 562.2 ns) > std dev 109.5 ps (74.48 ps .. 182.3 ps) > > benchmarking use longNeedle in longHaystack/lib > time 195.7 ?s (193.3 ?s .. 197.3 ?s) > 0.999 R? (0.999 R? .. 1.000 R?) > mean 191.9 ?s (191.1 ?s .. 193.0 ?s) > std dev 3.065 ?s (2.169 ?s .. 3.825 ?s) > > benchmarking use longNeedle in longHaystack/Milan > time 170.6 ?s (165.7 ?s .. 173.4 ?s) > 0.996 R? (0.995 R? .. 0.998 R?) > mean 160.8 ?s (158.6 ?s .. 163.5 ?s) > std dev 7.928 ?s (6.085 ?s .. 9.063 ?s) > variance introduced by outliers: 49% (moderately inflated) > > benchmarking use longNeedle in longHaystack/Abel > time 170.4 ?s (165.4 ?s .. 173.2 ?s) > 0.996 R? (0.995 R? .. 0.997 R?) > mean 160.5 ?s (158.3 ?s .. 163.3 ?s) > std dev 8.066 ?s (6.200 ?s .. 9.280 ?s) > variance introduced by outliers: 50% (moderately inflated) > > This is 64-bit on a recent i5. > > I appreciate learning something new from this discussion, so to pay it > forward please find attached a self-contained lhs for your nano-tweaking > pleasure. > > > -- Kim-Ee > > On Tue, Oct 14, 2014 at 6:02 AM, David Feuer > wrote: > > I've switched my allegiance from my own version to Milan's, because > it's a tad faster, and also less verbose. One thing to watch out > for: although I don't particularly like this, the current version in > Data.List makes [] `isSuffixOf` undefined = True. Unless there's a > general consensus that this doesn't matter, we need to preserve it. > > I don't think Milan's version is too terribly verbose. I tested > something very similar to your #1 that was proposed on IRC by Reid > Barton, and the numbers just didn't look too wonderful. I don't > think Milan's version is too terribly verbose, and I think it's > clearer than your #2. As for the depth of caring about speed, I > generally disagree with you: lists are actually very good for some > purposes, and, moreover, even when they're *not*, people use them > anyway and then other people wait for that code to run. > > On Mon, Oct 13, 2014 at 6:10 PM, Kim-Ee Yeoh > wrote: > > > On Tue, Oct 14, 2014 at 1:17 AM, David Feuer > > wrote: > > I've done the benchmarks and the results are clear: the > implementation I gave is faster than the one you gave and > the one in Data.List in all cases. Yours is usually faster > than the one in Data.List, but slower for very short lists. > > > The 2x factor you're seeing over Andreas's diminishes once we > put slightly more effort into an apples-to-apples comparison. > > 1. Instead of drop (length xs) ys, let's define the equivalent > > dropl :: [b] -> [a] -> [a] > dropl (_:xs) (_:ys) = dropl xs ys > dropl [] ys = ys > dropl xs [] = [] > > i.e. dropl xs ys ~ drop (length xs) ys. > > Now with Andreas's original version: > > xs `isSuffixOfA` ys = xs == dropl (dropl xs ys) ys > > that 2x gap narrows down to 10% for most cases. > > 2. There's that fast path which you optimize for, where the > needle is patently too long to be in the haystack. To narrow the > semantic gap, we can write > > dropm :: [b] -> [a] -> Maybe [a] > dropm (_:xs) (_:ys) = dropm xs ys > dropm [] ys = Just ys > dropm _ [] = Nothing > > xs `isSuffixOfA` ys = maybe False id $ do > zs <- dropm xs ys > ws <- dropm zs ys -- ws = needle-sized slice of the end > of haystack > return $ xs == ws > > Now, the long-needle-short-haystack case also becomes merely 10% > off. > > I'm -1 on both your proposal and the no.2 code because it's too > much verbosity for uncertain gain. The benchmarks look good, but > is the function even the bottleneck? For folks that care deeply > about speed, lists is almost always the wrong datatype anyway. > > I'm weakly +1 on no.1 because it beats the current double > reverse definition! > > -- Kim-Ee > > > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From abela at chalmers.se Wed Oct 15 00:32:39 2014 From: abela at chalmers.se (Andreas Abel) Date: Wed, 15 Oct 2014 02:32:39 +0200 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: <543D9494.2040309@ifi.lmu.de> References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> <543D9494.2040309@ifi.lmu.de> Message-ID: <543DC0A7.9020007@chalmers.se> Rowing back, I first did the proofs for Variant 1: drop (length ys - length xs) ys == xs Variant 2: drop (length (drop (length xs) ys)) ys == xs Here is the one for Variant 1: open import Data.List open import Data.List.Properties open import Data.Nat using (?; zero; suc; _+_; pred; _?_) open import Data.Nat.Properties open import Data.Nat.Properties.Simple open import Data.Product open import Relation.Binary.PropositionalEquality as ? open ?-Reasoning -- Two trivial lemmata about append. postulate append-nil : ?{A : Set} (xs : List A) ? xs ++ [] ? xs append-assoc : ?{A : Set} (xs ys zs : List A) ? xs ++ (ys ++ zs) ? (xs ++ ys) ++ zs -- Logical definition of suffix. _IsSuffixOf_ : ?{A} ? List A ? List A ? Set ys IsSuffixOf zs = ? ? xs ? xs ++ ys ? zs -- Lemma: drop always returns a suffix. drop-suffix : ?{A : Set} (n : ?) (xs : List A) ? drop n xs IsSuffixOf xs drop-suffix 0 xs = [] , refl drop-suffix (suc n) [] = [] , refl drop-suffix (suc n) (x ? xs) with drop-suffix n xs ... | ws , p = (x ? ws) , cong (? zs ? x ? zs) p -- Lemma: dropping after prefixing is the identity. drop-prefix : ?{A : Set} (ws xs : List A) ? drop (length ws) (ws ++ xs) ? xs drop-prefix [] xs = refl drop-prefix (w ? ws) xs = drop-prefix ws xs -- Variant 1: compute candiate for xs being suffix ys by -- -- drop (length ys - length xs) ys module LengthDiff where -- Soundness of suffix-test. drop-monus-suffix : ?{A : Set} (xs ys : List A) ? drop (length ys ? length xs) ys ? xs ? xs IsSuffixOf ys drop-monus-suffix xs ys p = subst (? ws ? ws IsSuffixOf ys) p (drop-suffix (length ys ? length xs) ys) -- Lemma: Substracting the length of an added suffix -- gives the length of the original list. length-monus-suffix : ?{A : Set} (ws xs : List A) ? length (ws ++ xs) ? length xs ? length ws length-monus-suffix ws xs = begin length (ws ++ xs) ? length xs ?? cong (? l ? l ? length xs) (length-++ ws) ? length ws + length xs ? length xs ?? m+n?n?m (length ws) (length xs) ? length ws ? -- Lemma: Dropping the a prefix computed from the length of the whole list. drop-prefix+- : ?{A : Set} (ws xs : List A) ? drop (length (ws ++ xs) ? length xs) (ws ++ xs) ? xs drop-prefix+- ws xs = begin drop (length (ws ++ xs) ? length xs) (ws ++ xs) ?? cong (? l ? drop l (ws ++ xs)) (length-monus-suffix ws xs) ? drop (length ws) (ws ++ xs) ?? drop-prefix ws xs ? xs ? -- Completeness of suffix-test. suffix-drop-monus : ?{A : Set} (xs ys : List A) ? xs IsSuffixOf ys ? drop (length ys ? length xs) ys ? xs suffix-drop-monus xs .(ws ++ xs) (ws , refl) = drop-prefix+- ws xs On 14.10.2014 23:24, Andreas Abel wrote: > It would be interesting to compare the correctness arguments for the > different versions of isSuffixOf. I gave the dropl-version a try in > Agda, but it is not trivial, I could not finish in 90 min. Here is a > start: > > open import Data.List > open import Data.Product > > open import Relation.Binary.PropositionalEquality as ? > > postulate > append-[] : ?{A : Set} {xs : List A} ? xs ++ [] ? xs > cong-tail : ?{A : Set} {x y : A} {xs ys} ? x ? xs ? y ? ys ? xs ? ys > > dropL : ?{A B : Set} ? List A ? List B ? List B > dropL [] ys = ys > dropL xs [] = [] > dropL (x ? xs) (y ? ys) = dropL xs ys > > dropL-is-drop-length : ?{A B : Set} (xs : List A) (ys : List B) ? > dropL xs ys ? drop (length xs) ys > dropL-is-drop-length [] ys = refl > dropL-is-drop-length (x ? xs) [] = refl > dropL-is-drop-length (x ? xs) (y ? ys) = dropL-is-drop-length xs ys > > -- Logical definition of suffix: > > _IsSuffixOf_ : ?{A} ? List A ? List A ? Set > ys IsSuffixOf zs = ? ? xs ? xs ++ ys ? zs > > dropL-suffix : ?{A B : Set} (xs : List A) (ys : List B) ? > dropL xs ys IsSuffixOf ys > dropL-suffix [] ys = [] , refl > dropL-suffix (x ? xs) [] = [] , refl > dropL-suffix (x ? xs) (y ? ys) with dropL-suffix xs ys > ... | ws , p = (y ? ws) , cong (? zs ? y ? zs) p > > -- This is one direction, rather easy: > > dropL-dropL-suffix : ?{A : Set} (xs ys : List A) ? > dropL (dropL xs ys) ys ? xs ? xs IsSuffixOf ys > dropL-dropL-suffix xs ys p = subst (? ws ? ws IsSuffixOf ys) p > (dropL-suffix (dropL xs ys) ys) > > -- One more easy lemma: > > dropL-diag : ?{A : Set} (xs : List A) ? dropL xs xs ? [] > dropL-diag [] = refl > dropL-diag (x ? xs) = dropL-diag xs > > -- The other direction, hard: > > suffix-dropL-dropL : ?{A : Set} (xs ys : List A) ? > xs IsSuffixOf ys ? dropL (dropL xs ys) ys ? xs > suffix-dropL-dropL xs .xs ([] , refl) rewrite dropL-diag xs = refl > suffix-dropL-dropL xs [] (w ? ws , ()) > suffix-dropL-dropL [] (y ? ys) (w ? ws , p) = dropL-diag ys > suffix-dropL-dropL (x ? xs) (y ? ys) (w ? ws , p) = {!suffix-dropL-dropL > (x ? xs) ys (ws , cong-tail p)!} > > -- stuck here. > > On 14.10.2014 15:05, Kim-Ee Yeoh wrote: >> David, >> >> To paraphrase Kernighan, ascertaining correctness is twice as hard as >> writing a program in the first place. So if you're as clever as possible >> with your code, how will you know it's even correct? >> >> Case in point: the infinite lists wrinkle that you started the thread >> with. /At a glance/ what do the general recursion versions (yours and >> Milan's) evaluate to on infinite lists? What are the benchmarks on the >> time it takes for a haskell programmer to figure them out? Would they >> not jump at the greater affordance of reasoning with Andreas's >> compositions? >> >> Meaning and reasonableness have always been the hallmarks of core libs. >> >> Least of all, since it's so losering to benchmark the wrong thing, see >> below on how Andreas-dropl no.1 beats out David-Milan by the tiniest >> sliver in short-needle-long-haystack. Like checking file extensions in >> pathnames that we saw in Andreas's Agda code. Here a concrete app brings >> real meaning to the timings as opposed to optimizing for vaporware. >> Watch them Agdaists fall off their chairs when they hit the speed boost. >> >> Don't mean to preach to the choir. Only layin' down the facts for the >> sake of the archive that every boiled haskeller knows to switch >> datatypes if isSuffixOf becomes the bottleneck. >> >> benchmarking simple shortNeedle in shortHaystack/lib >> time 176.6 ns (176.4 ns .. 177.0 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 176.6 ns (176.5 ns .. 176.9 ns) >> std dev 596.3 ps (318.4 ps .. 1.096 ns) >> >> benchmarking simple shortNeedle in shortHaystack/Milan >> time 135.6 ns (135.6 ns .. 135.6 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 135.6 ns (135.6 ns .. 135.6 ns) >> std dev 45.49 ps (23.88 ps .. 79.14 ps) >> >> benchmarking simple shortNeedle in shortHaystack/Abel >> time 145.6 ns (142.5 ns .. 149.5 ns) >> 0.996 R? (0.996 R? .. 0.997 R?) >> mean 147.3 ns (144.8 ns .. 150.0 ns) >> std dev 8.616 ns (8.070 ns .. 9.037 ns) >> variance introduced by outliers: 76% (severely inflated) >> >> benchmarking simple shortNeedle in longHaystack/lib >> time 71.12 ?s (71.08 ?s .. 71.15 ?s) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 71.12 ?s (71.08 ?s .. 71.16 ?s) >> std dev 142.7 ns (115.6 ns .. 186.3 ns) >> >> benchmarking simple shortNeedle in longHaystack/Milan >> time 45.00 ?s (44.99 ?s .. 45.00 ?s) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 45.00 ?s (45.00 ?s .. 45.01 ?s) >> std dev 21.04 ns (15.62 ns .. 28.75 ns) >> >> benchmarking simple shortNeedle in longHaystack/Abel >> time 43.68 ?s (43.68 ?s .. 43.70 ?s) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 43.69 ?s (43.68 ?s .. 43.69 ?s) >> std dev 18.29 ns (12.79 ns .. 27.76 ns) >> >> benchmarking simple longNeedle in shortHaystack/lib >> time 396.3 ns (396.2 ns .. 396.6 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 396.6 ns (396.3 ns .. 397.0 ns) >> std dev 1.106 ns (707.9 ps .. 1.662 ns) >> >> benchmarking simple longNeedle in shortHaystack/Milan >> time 117.9 ns (117.9 ns .. 118.0 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 117.9 ns (117.9 ns .. 117.9 ns) >> std dev 49.08 ps (30.66 ps .. 75.20 ps) >> >> benchmarking simple longNeedle in shortHaystack/Abel >> time 125.6 ns (125.6 ns .. 125.6 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 125.6 ns (125.6 ns .. 125.6 ns) >> std dev 35.17 ps (19.08 ps .. 58.78 ps) >> >> benchmarking simple longNeedle in longHaystack/lib >> time 71.98 ?s (71.92 ?s .. 72.03 ?s) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 71.93 ?s (71.85 ?s .. 72.00 ?s) >> std dev 247.4 ns (199.9 ns .. 305.3 ns) >> >> benchmarking simple longNeedle in longHaystack/Milan >> time 47.26 ?s (47.24 ?s .. 47.29 ?s) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 47.28 ?s (47.27 ?s .. 47.29 ?s) >> std dev 35.43 ns (28.70 ns .. 45.80 ns) >> >> benchmarking simple longNeedle in longHaystack/Abel >> time 47.44 ?s (47.43 ?s .. 47.45 ?s) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 47.44 ?s (47.44 ?s .. 47.45 ?s) >> std dev 16.81 ns (10.63 ns .. 28.75 ns) >> >> benchmarking use shortNeedle in shortHaystack/lib >> time 617.9 ns (616.8 ns .. 618.7 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 617.9 ns (616.9 ns .. 618.4 ns) >> std dev 2.295 ns (977.3 ps .. 3.747 ns) >> >> benchmarking use shortNeedle in shortHaystack/Milan >> time 570.7 ns (570.6 ns .. 570.8 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 570.7 ns (570.6 ns .. 570.7 ns) >> std dev 194.8 ps (154.1 ps .. 262.9 ps) >> >> benchmarking use shortNeedle in shortHaystack/Abel >> time 576.8 ns (575.5 ns .. 579.5 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 576.5 ns (575.7 ns .. 578.9 ns) >> std dev 5.133 ns (149.4 ps .. 9.882 ns) >> >> benchmarking use shortNeedle in longHaystack/lib >> time 194.4 ?s (192.0 ?s .. 195.9 ?s) >> 0.999 R? (0.999 R? .. 1.000 R?) >> mean 190.9 ?s (190.2 ?s .. 191.9 ?s) >> std dev 2.789 ?s (1.938 ?s .. 3.452 ?s) >> >> benchmarking use shortNeedle in longHaystack/Milan >> time 169.3 ?s (164.6 ?s .. 171.8 ?s) >> 0.997 R? (0.996 R? .. 0.998 R?) >> mean 160.1 ?s (158.1 ?s .. 162.6 ?s) >> std dev 7.419 ?s (5.720 ?s .. 8.512 ?s) >> variance introduced by outliers: 46% (moderately inflated) >> >> benchmarking use shortNeedle in longHaystack/Abel >> time 166.4 ?s (162.9 ?s .. 168.4 ?s) >> 0.998 R? (0.997 R? .. 0.999 R?) >> mean 159.1 ?s (157.5 ?s .. 161.0 ?s) >> std dev 5.903 ?s (4.471 ?s .. 6.721 ?s) >> variance introduced by outliers: 35% (moderately inflated) >> >> benchmarking use longNeedle in shortHaystack/lib >> time 828.0 ns (827.8 ns .. 828.2 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 828.0 ns (827.9 ns .. 828.2 ns) >> std dev 582.1 ps (339.9 ps .. 970.5 ps) >> >> benchmarking use longNeedle in shortHaystack/Milan >> time 550.0 ns (550.0 ns .. 550.1 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 550.0 ns (550.0 ns .. 550.1 ns) >> std dev 223.1 ps (97.52 ps .. 438.8 ps) >> >> benchmarking use longNeedle in shortHaystack/Abel >> time 562.1 ns (562.1 ns .. 562.2 ns) >> 1.000 R? (1.000 R? .. 1.000 R?) >> mean 562.1 ns (562.1 ns .. 562.2 ns) >> std dev 109.5 ps (74.48 ps .. 182.3 ps) >> >> benchmarking use longNeedle in longHaystack/lib >> time 195.7 ?s (193.3 ?s .. 197.3 ?s) >> 0.999 R? (0.999 R? .. 1.000 R?) >> mean 191.9 ?s (191.1 ?s .. 193.0 ?s) >> std dev 3.065 ?s (2.169 ?s .. 3.825 ?s) >> >> benchmarking use longNeedle in longHaystack/Milan >> time 170.6 ?s (165.7 ?s .. 173.4 ?s) >> 0.996 R? (0.995 R? .. 0.998 R?) >> mean 160.8 ?s (158.6 ?s .. 163.5 ?s) >> std dev 7.928 ?s (6.085 ?s .. 9.063 ?s) >> variance introduced by outliers: 49% (moderately inflated) >> >> benchmarking use longNeedle in longHaystack/Abel >> time 170.4 ?s (165.4 ?s .. 173.2 ?s) >> 0.996 R? (0.995 R? .. 0.997 R?) >> mean 160.5 ?s (158.3 ?s .. 163.3 ?s) >> std dev 8.066 ?s (6.200 ?s .. 9.280 ?s) >> variance introduced by outliers: 50% (moderately inflated) >> >> This is 64-bit on a recent i5. >> >> I appreciate learning something new from this discussion, so to pay it >> forward please find attached a self-contained lhs for your nano-tweaking >> pleasure. >> >> >> -- Kim-Ee >> >> On Tue, Oct 14, 2014 at 6:02 AM, David Feuer > > wrote: >> >> I've switched my allegiance from my own version to Milan's, because >> it's a tad faster, and also less verbose. One thing to watch out >> for: although I don't particularly like this, the current version in >> Data.List makes [] `isSuffixOf` undefined = True. Unless there's a >> general consensus that this doesn't matter, we need to preserve it. >> >> I don't think Milan's version is too terribly verbose. I tested >> something very similar to your #1 that was proposed on IRC by Reid >> Barton, and the numbers just didn't look too wonderful. I don't >> think Milan's version is too terribly verbose, and I think it's >> clearer than your #2. As for the depth of caring about speed, I >> generally disagree with you: lists are actually very good for some >> purposes, and, moreover, even when they're *not*, people use them >> anyway and then other people wait for that code to run. >> >> On Mon, Oct 13, 2014 at 6:10 PM, Kim-Ee Yeoh > > wrote: >> >> >> On Tue, Oct 14, 2014 at 1:17 AM, David Feuer >> > wrote: >> >> I've done the benchmarks and the results are clear: the >> implementation I gave is faster than the one you gave and >> the one in Data.List in all cases. Yours is usually faster >> than the one in Data.List, but slower for very short lists. >> >> >> The 2x factor you're seeing over Andreas's diminishes once we >> put slightly more effort into an apples-to-apples comparison. >> >> 1. Instead of drop (length xs) ys, let's define the equivalent >> >> dropl :: [b] -> [a] -> [a] >> dropl (_:xs) (_:ys) = dropl xs ys >> dropl [] ys = ys >> dropl xs [] = [] >> >> i.e. dropl xs ys ~ drop (length xs) ys. >> >> Now with Andreas's original version: >> >> xs `isSuffixOfA` ys = xs == dropl (dropl xs ys) ys >> >> that 2x gap narrows down to 10% for most cases. >> >> 2. There's that fast path which you optimize for, where the >> needle is patently too long to be in the haystack. To narrow the >> semantic gap, we can write >> >> dropm :: [b] -> [a] -> Maybe [a] >> dropm (_:xs) (_:ys) = dropm xs ys >> dropm [] ys = Just ys >> dropm _ [] = Nothing >> >> xs `isSuffixOfA` ys = maybe False id $ do >> zs <- dropm xs ys >> ws <- dropm zs ys -- ws = needle-sized slice of the end >> of haystack >> return $ xs == ws >> >> Now, the long-needle-short-haystack case also becomes merely 10% >> off. >> >> I'm -1 on both your proposal and the no.2 code because it's too >> much verbosity for uncertain gain. The benchmarks look good, but >> is the function even the bottleneck? For folks that care deeply >> about speed, lists is almost always the wrong datatype anyway. >> >> I'm weakly +1 on no.1 because it beats the current double >> reverse definition! >> >> -- Kim-Ee >> >> >> >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> > > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ -------------- next part -------------- open import Data.List open import Data.List.Properties open import Data.Nat using (?; zero; suc; _+_; pred; _?_) open import Data.Nat.Properties open import Data.Nat.Properties.Simple open import Data.Product open import Relation.Binary.PropositionalEquality as ? open ?-Reasoning -- Two trivial lemmata about append. postulate append-nil : ?{A : Set} (xs : List A) ? xs ++ [] ? xs append-assoc : ?{A : Set} (xs ys zs : List A) ? xs ++ (ys ++ zs) ? (xs ++ ys) ++ zs -- Logical definition of suffix. _IsSuffixOf_ : ?{A} ? List A ? List A ? Set ys IsSuffixOf zs = ? ? xs ? xs ++ ys ? zs -- Lemma: drop always returns a suffix. drop-suffix : ?{A : Set} (n : ?) (xs : List A) ? drop n xs IsSuffixOf xs drop-suffix 0 xs = [] , refl drop-suffix (suc n) [] = [] , refl drop-suffix (suc n) (x ? xs) with drop-suffix n xs ... | ws , p = (x ? ws) , cong (? zs ? x ? zs) p -- Lemma: dropping after prefixing is the identity. drop-prefix : ?{A : Set} (ws xs : List A) ? drop (length ws) (ws ++ xs) ? xs drop-prefix [] xs = refl drop-prefix (w ? ws) xs = drop-prefix ws xs -- Lemma: dropping all returns the empty list. drop-all : ?{A : Set} (xs : List A) ? drop (length xs) xs ? [] drop-all [] = refl drop-all (x ? xs) = drop-all xs -- Variant 1: compute candiate for xs being suffix ys by -- -- drop (length ys - length xs) ys module LengthDiff where -- Soundness of suffix-test. drop-monus-suffix : ?{A : Set} (xs ys : List A) ? drop (length ys ? length xs) ys ? xs ? xs IsSuffixOf ys drop-monus-suffix xs ys p = subst (? ws ? ws IsSuffixOf ys) p (drop-suffix (length ys ? length xs) ys) -- Lemma: Substracting the length of an added suffix -- gives the length of the original list. length-monus-suffix : ?{A : Set} (ws xs : List A) ? length (ws ++ xs) ? length xs ? length ws length-monus-suffix ws xs = begin length (ws ++ xs) ? length xs ?? cong (? l ? l ? length xs) (length-++ ws) ? length ws + length xs ? length xs ?? m+n?n?m (length ws) (length xs) ? length ws ? -- Lemma: Dropping the a prefix computed from the length of the whole list. drop-prefix+- : ?{A : Set} (ws xs : List A) ? drop (length (ws ++ xs) ? length xs) (ws ++ xs) ? xs drop-prefix+- ws xs = begin drop (length (ws ++ xs) ? length xs) (ws ++ xs) ?? cong (? l ? drop l (ws ++ xs)) (length-monus-suffix ws xs) ? drop (length ws) (ws ++ xs) ?? drop-prefix ws xs ? xs ? -- Completeness of suffix-test. suffix-drop-monus : ?{A : Set} (xs ys : List A) ? xs IsSuffixOf ys ? drop (length ys ? length xs) ys ? xs suffix-drop-monus xs .(ws ++ xs) (ws , refl) = drop-prefix+- ws xs -- Variant 2: compute candiate for xs being suffix ys by -- -- drop (length (drop length xs) ys) ys module LengthDrop where -- Soundness of suffix-test. drop-length-suffix : ?{A : Set} (xs ys : List A) ? drop (length (drop (length xs) ys)) ys ? xs ? xs IsSuffixOf ys drop-length-suffix xs ys p = subst (? ws ? ws IsSuffixOf ys) p (drop-suffix (length (drop (length xs) ys)) ys) -- Lemma. length-drop-suffix : ?{A : Set} (ws xs : List A) ? length (drop (length xs) (ws ++ xs)) ? length ws length-drop-suffix ws [] = cong length (append-nil ws) length-drop-suffix [] (x ? xs) = cong length (drop-all xs) length-drop-suffix (w ? ws) (x ? xs) = begin length (drop (length (x ? xs)) (w ? ws ++ x ? xs)) ??? length (drop (length xs) (ws ++ x ? xs)) ?? cong (? ys ? length (drop (length xs) ys)) (append-assoc ws (x ? []) xs) ? length (drop (length xs) ((ws ++ x ? []) ++ xs)) ?? length-drop-suffix (ws ++ x ? []) xs ? length (ws ++ x ? []) ?? length-++ ws ? length ws + 1 ?? +-comm _ 1 ? length (w ? ws) ? -- Lemma 2. drop-prefix+- : ?{A : Set} (ws xs : List A) ? drop (length (drop (length xs) (ws ++ xs))) (ws ++ xs) ? xs drop-prefix+- ws xs = begin drop (length (drop (length xs) (ws ++ xs))) (ws ++ xs) ?? cong (? l ? drop l (ws ++ xs)) (length-drop-suffix ws xs) ? drop (length ws) (ws ++ xs) ?? drop-prefix ws xs ? xs ? -- Completeness of suffix-test. suffix-drop-length : ?{A : Set} (xs ys : List A) ? xs IsSuffixOf ys ? drop (length (drop (length xs) ys)) ys ? xs suffix-drop-length xs .(ws ++ xs) (ws , refl) = drop-prefix+- ws xs -- There should be a short way from Variant 1 to Variant 2 proving -- length (drop (length xs) ys) ? length ys ? length xs From ky3 at atamo.com Thu Oct 16 02:56:20 2014 From: ky3 at atamo.com (Kim-Ee Yeoh) Date: Thu, 16 Oct 2014 09:56:20 +0700 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: <543DC0A7.9020007@chalmers.se> References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> <543D9494.2040309@ifi.lmu.de> <543DC0A7.9020007@chalmers.se> Message-ID: On Wed, Oct 15, 2014 at 7:32 AM, Andreas Abel wrote: > Rowing back, I first did the proofs for > > Variant 1: drop (length ys - length xs) ys == xs > > Variant 2: drop (length (drop (length xs) ys)) ys == xs > Fab! In 10 years once I'm fearsome like Andreas I shall take a tilt at Agdaizing David-Milan. Meanwhile I wonder if Agda can perform the following proof-to-proof transformation. Let's let-expand Andreas-dropl like this: ns `isSuffixOfA` hs = let delta = dropl ns hs in ns == dropl delta hs Recall dropl ns hs ~ drop (length ns) hs. But needle longer than haystack is a D.O.A. If only there was a kill-switch we could flip. Cue Maybe as exceptions lite to provide just the thing: ns `isSuffixOfA` hs = fromMaybe False $ do delta <- dropm ns hs return $ ns == dropl delta hs Here's dropm and note how dropl ns hs ~ fromMaybe [] $ dropm ns hs. dropm :: [b] -> [a] -> Maybe [a] dropm (_:xs) (_:ys) = dropm xs ys dropm [] ys = Just ys dropm _ [] = Nothing -- xs longer than ys I put it to you that this new, improved, effectivized version is equivalent to David-Milan. Not forgetting that the right combinators will do-desugar back to a one-liner. Indeed the benchmarks show that M-A-d still pips out D-M in short-long. Best of all, the gap in everything else has shrunk to small single digits. E.g. short-short has narrowed from 9% to 2%: benchmarking simple shortNeedle in shortHaystack/Milan time 136.3 ns (136.2 ns .. 136.3 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 136.3 ns (136.3 ns .. 136.4 ns) std dev 222.5 ps (36.51 ps .. 466.3 ps) benchmarking simple shortNeedle in shortHaystack/Abel time 139.7 ns (139.6 ns .. 139.9 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 139.7 ns (139.6 ns .. 139.9 ns) std dev 477.6 ps (296.8 ps .. 782.9 ps) benchmarking simple shortNeedle in longHaystack/Milan time 44.91 ?s (44.91 ?s .. 44.92 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 44.91 ?s (44.91 ?s .. 44.92 ?s) std dev 14.94 ns (12.14 ns .. 20.34 ns) benchmarking simple shortNeedle in longHaystack/Abel time 43.57 ?s (43.57 ?s .. 43.58 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 43.58 ?s (43.57 ?s .. 43.60 ?s) std dev 32.49 ns (11.69 ns .. 64.84 ns) benchmarking simple longNeedle in shortHaystack/Milan time 118.3 ns (118.3 ns .. 118.3 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 118.3 ns (118.3 ns .. 118.3 ns) std dev 17.68 ps (13.54 ps .. 23.11 ps) benchmarking simple longNeedle in shortHaystack/Abel time 120.0 ns (120.0 ns .. 120.0 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 120.0 ns (120.0 ns .. 120.0 ns) std dev 12.54 ps (8.954 ps .. 16.97 ps) benchmarking simple longNeedle in longHaystack/Milan time 46.64 ?s (46.63 ?s .. 46.67 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 46.66 ?s (46.65 ?s .. 46.67 ?s) std dev 40.74 ns (29.39 ns .. 59.83 ns) benchmarking simple longNeedle in longHaystack/Abel time 47.25 ?s (47.23 ?s .. 47.26 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 47.25 ?s (47.24 ?s .. 47.26 ?s) std dev 22.33 ns (18.24 ns .. 27.98 ns) benchmarking simple shortNeedle in shortHaystack/Milan time 136.3 ns (136.2 ns .. 136.3 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 136.3 ns (136.3 ns .. 136.4 ns) std dev 222.5 ps (36.51 ps .. 466.3 ps) benchmarking simple shortNeedle in shortHaystack/Abel time 139.7 ns (139.6 ns .. 139.9 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 139.7 ns (139.6 ns .. 139.9 ns) std dev 477.6 ps (296.8 ps .. 782.9 ps) benchmarking simple shortNeedle in longHaystack/Milan time 44.91 ?s (44.91 ?s .. 44.92 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 44.91 ?s (44.91 ?s .. 44.92 ?s) std dev 14.94 ns (12.14 ns .. 20.34 ns) benchmarking simple shortNeedle in longHaystack/Abel time 43.57 ?s (43.57 ?s .. 43.58 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 43.58 ?s (43.57 ?s .. 43.60 ?s) std dev 32.49 ns (11.69 ns .. 64.84 ns) benchmarking simple longNeedle in shortHaystack/Milan time 118.3 ns (118.3 ns .. 118.3 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 118.3 ns (118.3 ns .. 118.3 ns) std dev 17.68 ps (13.54 ps .. 23.11 ps) benchmarking simple longNeedle in shortHaystack/Abel time 120.0 ns (120.0 ns .. 120.0 ns) 1.000 R? (1.000 R? .. 1.000 R?) mean 120.0 ns (120.0 ns .. 120.0 ns) std dev 12.54 ps (8.954 ps .. 16.97 ps) benchmarking simple longNeedle in longHaystack/Milan time 46.64 ?s (46.63 ?s .. 46.67 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 46.66 ?s (46.65 ?s .. 46.67 ?s) std dev 40.74 ns (29.39 ns .. 59.83 ns) benchmarking simple longNeedle in longHaystack/Abel time 47.25 ?s (47.23 ?s .. 47.26 ?s) 1.000 R? (1.000 R? .. 1.000 R?) mean 47.25 ?s (47.24 ?s .. 47.26 ?s) std dev 22.33 ns (18.24 ns .. 27.98 ns) Whether the 2% difference is due to Maybe's injecting additional bottoms is anyone's guess. Worth investigating is whether a core-to-core transformation can snap shut the gap, but 2% is already magnificent testimony to the efficacy of compositional, transformational, effectful programming that's uniquely Haskell. -- Kim-Ee -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Thu Oct 16 03:38:20 2014 From: david.feuer at gmail.com (David Feuer) Date: Wed, 15 Oct 2014 23:38:20 -0400 Subject: Proposal: Make a very slight change to the semantics of Data.List.isSuffixOf In-Reply-To: References: <20141010123453.GA14905@auryn.cz> <5438FF19.3040607@chalmers.se> <543A8CD5.8030603@chalmers.se> <543AA62E.8080403@chalmers.se> <543D9494.2040309@ifi.lmu.de> <543DC0A7.9020007@chalmers.se> Message-ID: Isn't this basically a clearer, more elegant version of my original implementation? I was somewhat surprised that GHC couldn't turn it into Milan's expression. I'm PERFECTLY HAPPY to go with your "effectivized maybe" version. It's clear, it's asymptotically optimal, and its overall performance is on par with the Milan one. On Wed, Oct 15, 2014 at 10:56 PM, Kim-Ee Yeoh wrote: > > On Wed, Oct 15, 2014 at 7:32 AM, Andreas Abel wrote: > >> Rowing back, I first did the proofs for >> >> Variant 1: drop (length ys - length xs) ys == xs >> >> Variant 2: drop (length (drop (length xs) ys)) ys == xs >> > > Fab! > > In 10 years once I'm fearsome like Andreas I shall take a tilt at > Agdaizing David-Milan. > > Meanwhile I wonder if Agda can perform the following proof-to-proof > transformation. > > Let's let-expand Andreas-dropl like this: > > ns `isSuffixOfA` hs = let > delta = dropl ns hs in > ns == dropl delta hs > > Recall dropl ns hs ~ drop (length ns) hs. > > But needle longer than haystack is a D.O.A. If only there was a > kill-switch we could flip. > > Cue Maybe as exceptions lite to provide just the thing: > > ns `isSuffixOfA` hs = fromMaybe False $ do > delta <- dropm ns hs > return $ ns == dropl delta hs > > Here's dropm and note how dropl ns hs ~ fromMaybe [] $ dropm ns hs. > > dropm :: [b] -> [a] -> Maybe [a] > dropm (_:xs) (_:ys) = dropm xs ys > dropm [] ys = Just ys > dropm _ [] = Nothing -- xs longer than ys > > I put it to you that this new, improved, effectivized version is > equivalent to David-Milan. Not forgetting that the right combinators will > do-desugar back to a one-liner. > > Indeed the benchmarks show that M-A-d still pips out D-M in short-long. > Best of all, the gap in everything else has shrunk to small single digits. > E.g. short-short has narrowed from 9% to 2%: > > benchmarking simple shortNeedle in shortHaystack/Milan > time 136.3 ns (136.2 ns .. 136.3 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 136.3 ns (136.3 ns .. 136.4 ns) > std dev 222.5 ps (36.51 ps .. 466.3 ps) > > benchmarking simple shortNeedle in shortHaystack/Abel > time 139.7 ns (139.6 ns .. 139.9 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 139.7 ns (139.6 ns .. 139.9 ns) > std dev 477.6 ps (296.8 ps .. 782.9 ps) > > benchmarking simple shortNeedle in longHaystack/Milan > time 44.91 ?s (44.91 ?s .. 44.92 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 44.91 ?s (44.91 ?s .. 44.92 ?s) > std dev 14.94 ns (12.14 ns .. 20.34 ns) > > benchmarking simple shortNeedle in longHaystack/Abel > time 43.57 ?s (43.57 ?s .. 43.58 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 43.58 ?s (43.57 ?s .. 43.60 ?s) > std dev 32.49 ns (11.69 ns .. 64.84 ns) > > benchmarking simple longNeedle in shortHaystack/Milan > time 118.3 ns (118.3 ns .. 118.3 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 118.3 ns (118.3 ns .. 118.3 ns) > std dev 17.68 ps (13.54 ps .. 23.11 ps) > > benchmarking simple longNeedle in shortHaystack/Abel > time 120.0 ns (120.0 ns .. 120.0 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 120.0 ns (120.0 ns .. 120.0 ns) > std dev 12.54 ps (8.954 ps .. 16.97 ps) > > benchmarking simple longNeedle in longHaystack/Milan > time 46.64 ?s (46.63 ?s .. 46.67 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 46.66 ?s (46.65 ?s .. 46.67 ?s) > std dev 40.74 ns (29.39 ns .. 59.83 ns) > > benchmarking simple longNeedle in longHaystack/Abel > time 47.25 ?s (47.23 ?s .. 47.26 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 47.25 ?s (47.24 ?s .. 47.26 ?s) > std dev 22.33 ns (18.24 ns .. 27.98 ns) > benchmarking simple shortNeedle in shortHaystack/Milan > time 136.3 ns (136.2 ns .. 136.3 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 136.3 ns (136.3 ns .. 136.4 ns) > std dev 222.5 ps (36.51 ps .. 466.3 ps) > > benchmarking simple shortNeedle in shortHaystack/Abel > time 139.7 ns (139.6 ns .. 139.9 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 139.7 ns (139.6 ns .. 139.9 ns) > std dev 477.6 ps (296.8 ps .. 782.9 ps) > > benchmarking simple shortNeedle in longHaystack/Milan > time 44.91 ?s (44.91 ?s .. 44.92 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 44.91 ?s (44.91 ?s .. 44.92 ?s) > std dev 14.94 ns (12.14 ns .. 20.34 ns) > > benchmarking simple shortNeedle in longHaystack/Abel > time 43.57 ?s (43.57 ?s .. 43.58 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 43.58 ?s (43.57 ?s .. 43.60 ?s) > std dev 32.49 ns (11.69 ns .. 64.84 ns) > > benchmarking simple longNeedle in shortHaystack/Milan > time 118.3 ns (118.3 ns .. 118.3 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 118.3 ns (118.3 ns .. 118.3 ns) > std dev 17.68 ps (13.54 ps .. 23.11 ps) > > benchmarking simple longNeedle in shortHaystack/Abel > time 120.0 ns (120.0 ns .. 120.0 ns) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 120.0 ns (120.0 ns .. 120.0 ns) > std dev 12.54 ps (8.954 ps .. 16.97 ps) > > benchmarking simple longNeedle in longHaystack/Milan > time 46.64 ?s (46.63 ?s .. 46.67 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 46.66 ?s (46.65 ?s .. 46.67 ?s) > std dev 40.74 ns (29.39 ns .. 59.83 ns) > > benchmarking simple longNeedle in longHaystack/Abel > time 47.25 ?s (47.23 ?s .. 47.26 ?s) > 1.000 R? (1.000 R? .. 1.000 R?) > mean 47.25 ?s (47.24 ?s .. 47.26 ?s) > std dev 22.33 ns (18.24 ns .. 27.98 ns) > > > Whether the 2% difference is due to Maybe's injecting additional bottoms > is anyone's guess. > > Worth investigating is whether a core-to-core transformation can snap shut > the gap, but 2% is already magnificent testimony to the efficacy of > compositional, transformational, effectful programming that's uniquely > Haskell. > > > -- Kim-Ee > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From sol at typeful.net Thu Oct 16 06:20:55 2014 From: sol at typeful.net (Simon Hengel) Date: Thu, 16 Oct 2014 14:20:55 +0800 Subject: Proposal: Improve error messages for (!!) (include index and length of list) Message-ID: <20141016030239.GA25378@x200> Hi, currently we have the following implementation for (!!): #ifdef USE_REPORT_PRELUDE xs !! n | n < 0 = error "Prelude.!!: negative index" [] !! _ = error "Prelude.!!: index too large" (x:_) !! 0 = x (_:xs) !! n = xs !! (n-1) #else -- HBC version (stolen), then unboxified xs !! (I# n0) | isTrue# (n0 <# 0#) = error "Prelude.(!!): negative index\n" | otherwise = sub xs n0 where sub :: [a] -> Int# -> a sub [] _ = error "Prelude.(!!): index too large\n" sub (y:ys) n = if isTrue# (n ==# 0#) then y else sub ys (n -# 1#) #endif I propose to change the error messages for the non-report version to include index and list length, something that is functionally equivalent to: xs !! (I# n0) | isTrue# (n0 <# 0#) = indexError xs n0 | otherwise = sub xs n0 where sub :: [a] -> Int# -> a sub [] _ = indexError xs n0 sub (y:ys) n = if isTrue# (n ==# 0#) then y else sub ys (n -# 1#) indexError :: [a] -> Int# -> b indexError xs (I# -> n) | n < 0 = error ("Prelude.(!!): negative index " ++ show n) | otherwise = error ("Prelude.(!!): index " ++ show n ++ " too large for list of length " ++ show (length xs)) Some usage examples: *Main> [1, 2, 3] !! (-1) *** Exception: Prelude.(!!): negative index -1 *Main> [1, 2, 3] !! 3 *** Exception: Prelude.(!!): index 3 too large for list of length 3 This will require some refactoring, i.e. we need to move itos from GHC.Show to e.g. GHC.Base. Discussion period: 2 weeks Cheers, Simon From david.feuer at gmail.com Thu Oct 16 06:40:41 2014 From: david.feuer at gmail.com (David Feuer) Date: Thu, 16 Oct 2014 02:40:41 -0400 Subject: Proposal: Improve error messages for (!!) (include index and length of list) In-Reply-To: <20141016030239.GA25378@x200> References: <20141016030239.GA25378@x200> Message-ID: I'm generally +1 on this concept, but I'd like to see some evidence that there is no measurable performance impact on nofib and perhaps also other benchmarks, particularly for very short ephemeral lists. Note that saving the index requires actually putting it somewhere. On Oct 16, 2014 2:21 AM, "Simon Hengel" wrote: > Hi, > currently we have the following implementation for (!!): > > #ifdef USE_REPORT_PRELUDE > xs !! n | n < 0 = error "Prelude.!!: negative index" > [] !! _ = error "Prelude.!!: index too large" > (x:_) !! 0 = x > (_:xs) !! n = xs !! (n-1) > #else > -- HBC version (stolen), then unboxified > xs !! (I# n0) | isTrue# (n0 <# 0#) = error "Prelude.(!!): negative > index\n" > | otherwise = sub xs n0 > where > sub :: [a] -> Int# -> a > sub [] _ = error "Prelude.(!!): index > too large\n" > sub (y:ys) n = if isTrue# (n ==# 0#) > then y > else sub ys (n -# 1#) > #endif > > I propose to change the error messages for the non-report version to > include index and list length, something that is functionally equivalent > to: > > xs !! (I# n0) | isTrue# (n0 <# 0#) = indexError xs n0 > | otherwise = sub xs n0 > where > > sub :: [a] -> Int# -> a > sub [] _ = indexError xs n0 > sub (y:ys) n = if isTrue# (n ==# 0#) > then y > else sub ys (n -# 1#) > indexError :: [a] -> Int# -> b > indexError xs (I# -> n) > | n < 0 = error ("Prelude.(!!): negative index " ++ show n) > | otherwise = error ("Prelude.(!!): index " ++ show n ++ " too large > for list of length " ++ show (length xs)) > > Some usage examples: > > *Main> [1, 2, 3] !! (-1) > *** Exception: Prelude.(!!): negative index -1 > *Main> [1, 2, 3] !! 3 > *** Exception: Prelude.(!!): index 3 too large for list of length 3 > > This will require some refactoring, i.e. we need to move itos from > GHC.Show to e.g. GHC.Base. > > Discussion period: 2 weeks > > Cheers, > Simon > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From hvr at gnu.org Thu Oct 16 10:39:58 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Thu, 16 Oct 2014 12:39:58 +0200 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package Message-ID: <87h9z4wb5t.fsf@gnu.org> The Proposal ============ I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in order to add Generics support to the `NFData` class based on the `-XDeriveGenerics` and `-XDefaultSignature` language extensions. A concrete patch is available for bike-review at [3] Prior Proposal & What's changed =============================== About 2 years ago, I already proposed something similar[4]. Back then the major concern was avoiding a conditionally exported API as using the (back then) rather young `Generics` extension would leave the Haskell98 domain. This lead to me release Generics support as a companion package[2] which turns out to have become a rather popular package (judging from the Hackage download-count stats). I only realized after the discussion was effectively finished, that having a separate `deepseq-generics` actually does have an IMO non-neglectable downside: You can't support a `DefaultSignature`-based default implementation, as those need to be backed into the `NFData` class. Missing out on `DefaultSignature` would be a shame IMO, because * There's a chance that starting with GHC 7.10 `deriving` may work for arbitrary classes[5], putting `NFData` on equal footing as built-in classes such as `Eq` or `Show`. Specifically, you would be able to write data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char) deriving (Show, Generic, NFData) instead of having to manually write the following boilerplate instance NFData Foo where rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z rnf (Bar x) = rnf x which gets tedious rather soon if you have many (and more complex) types and tend to refactor regularly (with a risk of failing to adapt your manual instances if you change the strictness of fields) * The current default `rnf` implementation, i.e. rnf a = a `seq` () is rather error-prone, as it's *very* easy to end up with an incorrect instance. Especially after refactoring a type for which the NF=WHNF assumption was broken after refactoring by adding new fields, or changing the strictness of existing fields. The Generics-derived `rnf` implementation does not have such a problem. Moreover, popular packages are starting adopt (and even recommend) the use of Generics in combination with `DefaultSignature` to provide automatically derived default instances, most notably `hashable`[6], `binary`[7], or `aeson`[8] just to name a few. In addition to providing a precedence for the use of Generics, I consider those packages evidence for Generics to have proven itself to the point of replacing TemplateHaskell in these use-cases. Compatibility & Breakage Considerations ======================================= * This change requires a major version bump to deepseq-1.4.0 * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first version to support Generics & `DefaultSignature`. * Code relying on the current `rnf` default-implementation will most likely break (unless a `Generics` instance happens to be in-place) However, it's easy to provide forward/backward-compatibility w/o any CPP, by simply explicitly defining instance NFData XYZ where rnf = seq x () Discussion Period: 2 weeks [1]: http://hackage.haskell.org/package/deepseq [2]: http://hackage.haskell.org/package/deepseq-generics [3]: https://github.com/haskell/deepseq/pull/1 [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940 [5]: https://ghc.haskell.org/trac/ghc/ticket/5462 [6]: http://hackage.haskell.org/package/hashable [7]: http://hackage.haskell.org/package/binary [8]: http://hackage.haskell.org/package/aeson From dreixel at gmail.com Thu Oct 16 10:43:59 2014 From: dreixel at gmail.com (=?UTF-8?Q?Jos=C3=A9_Pedro_Magalh=C3=A3es?=) Date: Thu, 16 Oct 2014 11:43:59 +0100 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: <87h9z4wb5t.fsf@gnu.org> References: <87h9z4wb5t.fsf@gnu.org> Message-ID: On Thu, Oct 16, 2014 at 11:39 AM, Herbert Valerio Riedel wrote: > > * There's a chance that starting with GHC 7.10 `deriving` may work for > arbitrary classes[5], putting `NFData` on equal footing as built-in > classes such as `Eq` or `Show`. A very high chance, I hope! :-) I'm all in favour of this proposal. Cheers, Pedro -------------- next part -------------- An HTML attachment was scrubbed... URL: From hvr at gnu.org Thu Oct 16 11:46:09 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Thu, 16 Oct 2014 13:46:09 +0200 Subject: Proposal: Improve error messages for (!!) (include index and length of list) In-Reply-To: <20141016030239.GA25378@x200> (Simon Hengel's message of "Thu, 16 Oct 2014 14:20:55 +0800") References: <20141016030239.GA25378@x200> Message-ID: <87d29sw83i.fsf@gnu.org> On 2014-10-16 at 08:20:55 +0200, Simon Hengel wrote: [...] > I propose to change the error messages for the non-report version to > include index and list length, something that is functionally equivalent > to: While I'm very sympathetic to better error messages; doesn't the implementation you gave defer garbage-collecting the start of the list, by keeping the head of the list alive until either the desired index has been reached or end-of-list is detected? e.g. consider something (silly) like ([1..] !! 10000000) Cheers, hvr From nominolo at googlemail.com Thu Oct 16 12:13:39 2014 From: nominolo at googlemail.com (Thomas Schilling) Date: Thu, 16 Oct 2014 14:13:39 +0200 Subject: Proposal: Improve error messages for (!!) (include index and length of list) In-Reply-To: <87d29sw83i.fsf@gnu.org> References: <20141016030239.GA25378@x200> <87d29sw83i.fsf@gnu.org> Message-ID: Yes, you'd have to calculate the length on the fly. i.e., something like this (untested): xs !! n | n < 0 = error "... negative index ..." xs !! (I# n) = go xs n 0# where go [] idx len = error $ "... Index " ++ show (I# (idx +# len) ++ " too large for list of length " ++ show (I# len) go (x:_) 0# _ = x go (_:xs) idx len = go xs (idx -# 0#) (len +# 1#) On modern processors the extra addition and the extra parameter shouldn't hurt, though we'd need a benchmark to make sure, of course. You could also make the error message a bit less helpful and just return how far the index pointed past the end of the list. On 16 October 2014 13:46, Herbert Valerio Riedel wrote: > On 2014-10-16 at 08:20:55 +0200, Simon Hengel wrote: > > [...] > >> I propose to change the error messages for the non-report version to >> include index and list length, something that is functionally equivalent >> to: > > While I'm very sympathetic to better error messages; doesn't the > implementation you gave defer garbage-collecting the start of the list, > by keeping the head of the list alive until either the desired index has > been reached or end-of-list is detected? > > e.g. consider something (silly) like ([1..] !! 10000000) > > Cheers, > hvr > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries From spam at scientician.net Thu Oct 16 13:27:56 2014 From: spam at scientician.net (Bardur Arantsson) Date: Thu, 16 Oct 2014 15:27:56 +0200 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: <87h9z4wb5t.fsf@gnu.org> References: <87h9z4wb5t.fsf@gnu.org> Message-ID: On 2014-10-16 12:39, Herbert Valerio Riedel wrote: > > The Proposal > ============ > > I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in > order to add Generics support to the `NFData` class based on the > `-XDeriveGenerics` and `-XDefaultSignature` language extensions. > > A concrete patch is available for bike-review at [3] > +1 From david.feuer at gmail.com Thu Oct 16 13:36:07 2014 From: david.feuer at gmail.com (David Feuer) Date: Thu, 16 Oct 2014 09:36:07 -0400 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: <87h9z4wb5t.fsf@gnu.org> References: <87h9z4wb5t.fsf@gnu.org> Message-ID: I'm generally opposed to DefaultSignatures as an upside-down, insufficiently-general attempt to solve an important problem, and generally think the less relies on them the better. On Oct 16, 2014 6:40 AM, "Herbert Valerio Riedel" wrote: > > The Proposal > ============ > > I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in > order to add Generics support to the `NFData` class based on the > `-XDeriveGenerics` and `-XDefaultSignature` language extensions. > > A concrete patch is available for bike-review at [3] > > > Prior Proposal & What's changed > =============================== > > About 2 years ago, I already proposed something similar[4]. Back then > the major concern was avoiding a conditionally exported API as using the > (back then) rather young `Generics` extension would leave the Haskell98 > domain. > > This lead to me release Generics support as a companion package[2] which > turns out to have become a rather popular package (judging from the > Hackage download-count stats). > > I only realized after the discussion was effectively finished, that > having a separate `deepseq-generics` actually does have an IMO > non-neglectable downside: > > You can't support a `DefaultSignature`-based default implementation, > as those need to be backed into the `NFData` class. > > Missing out on `DefaultSignature` would be a shame IMO, because > > * There's a chance that starting with GHC 7.10 `deriving` may work for > arbitrary classes[5], putting `NFData` on equal footing as built-in > classes such as `Eq` or `Show`. Specifically, you would be able to > write > > data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char) > deriving (Show, Generic, NFData) > > instead of having to manually write the following boilerplate > > instance NFData Foo where > rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z > rnf (Bar x) = rnf x > > which gets tedious rather soon if you have many (and more complex) > types and tend to refactor regularly (with a risk of failing to adapt > your manual instances if you change the strictness of fields) > > > * The current default `rnf` implementation, i.e. > > rnf a = a `seq` () > > is rather error-prone, as it's *very* easy to end up with an > incorrect instance. Especially after refactoring a type for which the > NF=WHNF assumption was broken after refactoring by adding new fields, > or changing the strictness of existing fields. > > The Generics-derived `rnf` implementation does not have such a > problem. > > > Moreover, popular packages are starting adopt (and even recommend) the > use of Generics in combination with `DefaultSignature` to provide > automatically derived default instances, most notably `hashable`[6], > `binary`[7], or `aeson`[8] just to name a few. In addition to providing > a precedence for the use of Generics, I consider those packages evidence > for Generics to have proven itself to the point of replacing > TemplateHaskell in these use-cases. > > > Compatibility & Breakage Considerations > ======================================= > > * This change requires a major version bump to deepseq-1.4.0 > > * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first > version to support Generics & `DefaultSignature`. > > * Code relying on the current `rnf` default-implementation will most > likely break (unless a `Generics` instance happens to be in-place) > > However, it's easy to provide forward/backward-compatibility w/o any > CPP, by simply explicitly defining > > instance NFData XYZ where rnf = seq x () > > > > Discussion Period: 2 weeks > > > > [1]: http://hackage.haskell.org/package/deepseq > [2]: http://hackage.haskell.org/package/deepseq-generics > [3]: https://github.com/haskell/deepseq/pull/1 > [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940 > [5]: https://ghc.haskell.org/trac/ghc/ticket/5462 > [6]: http://hackage.haskell.org/package/hashable > [7]: http://hackage.haskell.org/package/binary > [8]: http://hackage.haskell.org/package/aeson > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From johan.tibell at gmail.com Thu Oct 16 13:52:00 2014 From: johan.tibell at gmail.com (Johan Tibell) Date: Thu, 16 Oct 2014 15:52:00 +0200 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: References: <87h9z4wb5t.fsf@gnu.org> Message-ID: Could you elaborate on this? What other existing options are better? On Thu, Oct 16, 2014 at 3:36 PM, David Feuer wrote: > I'm generally opposed to DefaultSignatures as an upside-down, > insufficiently-general attempt to solve an important problem, and generally > think the less relies on them the better. > On Oct 16, 2014 6:40 AM, "Herbert Valerio Riedel" wrote: > >> >> The Proposal >> ============ >> >> I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in >> order to add Generics support to the `NFData` class based on the >> `-XDeriveGenerics` and `-XDefaultSignature` language extensions. >> >> A concrete patch is available for bike-review at [3] >> >> >> Prior Proposal & What's changed >> =============================== >> >> About 2 years ago, I already proposed something similar[4]. Back then >> the major concern was avoiding a conditionally exported API as using the >> (back then) rather young `Generics` extension would leave the Haskell98 >> domain. >> >> This lead to me release Generics support as a companion package[2] which >> turns out to have become a rather popular package (judging from the >> Hackage download-count stats). >> >> I only realized after the discussion was effectively finished, that >> having a separate `deepseq-generics` actually does have an IMO >> non-neglectable downside: >> >> You can't support a `DefaultSignature`-based default implementation, >> as those need to be backed into the `NFData` class. >> >> Missing out on `DefaultSignature` would be a shame IMO, because >> >> * There's a chance that starting with GHC 7.10 `deriving` may work for >> arbitrary classes[5], putting `NFData` on equal footing as built-in >> classes such as `Eq` or `Show`. Specifically, you would be able to >> write >> >> data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char) >> deriving (Show, Generic, NFData) >> >> instead of having to manually write the following boilerplate >> >> instance NFData Foo where >> rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z >> rnf (Bar x) = rnf x >> >> which gets tedious rather soon if you have many (and more complex) >> types and tend to refactor regularly (with a risk of failing to adapt >> your manual instances if you change the strictness of fields) >> >> >> * The current default `rnf` implementation, i.e. >> >> rnf a = a `seq` () >> >> is rather error-prone, as it's *very* easy to end up with an >> incorrect instance. Especially after refactoring a type for which the >> NF=WHNF assumption was broken after refactoring by adding new fields, >> or changing the strictness of existing fields. >> >> The Generics-derived `rnf` implementation does not have such a >> problem. >> >> >> Moreover, popular packages are starting adopt (and even recommend) the >> use of Generics in combination with `DefaultSignature` to provide >> automatically derived default instances, most notably `hashable`[6], >> `binary`[7], or `aeson`[8] just to name a few. In addition to providing >> a precedence for the use of Generics, I consider those packages evidence >> for Generics to have proven itself to the point of replacing >> TemplateHaskell in these use-cases. >> >> >> Compatibility & Breakage Considerations >> ======================================= >> >> * This change requires a major version bump to deepseq-1.4.0 >> >> * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first >> version to support Generics & `DefaultSignature`. >> >> * Code relying on the current `rnf` default-implementation will most >> likely break (unless a `Generics` instance happens to be in-place) >> >> However, it's easy to provide forward/backward-compatibility w/o any >> CPP, by simply explicitly defining >> >> instance NFData XYZ where rnf = seq x () >> >> >> >> Discussion Period: 2 weeks >> >> >> >> [1]: http://hackage.haskell.org/package/deepseq >> [2]: http://hackage.haskell.org/package/deepseq-generics >> [3]: https://github.com/haskell/deepseq/pull/1 >> [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940 >> [5]: https://ghc.haskell.org/trac/ghc/ticket/5462 >> [6]: http://hackage.haskell.org/package/hashable >> [7]: http://hackage.haskell.org/package/binary >> [8]: http://hackage.haskell.org/package/aeson >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Thu Oct 16 13:57:49 2014 From: david.feuer at gmail.com (David Feuer) Date: Thu, 16 Oct 2014 09:57:49 -0400 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: References: <87h9z4wb5t.fsf@gnu.org> Message-ID: I don't know that any existing options *are* better. On Oct 16, 2014 9:52 AM, "Johan Tibell" wrote: > Could you elaborate on this? What other existing options are better? > > On Thu, Oct 16, 2014 at 3:36 PM, David Feuer > wrote: > >> I'm generally opposed to DefaultSignatures as an upside-down, >> insufficiently-general attempt to solve an important problem, and generally >> think the less relies on them the better. >> On Oct 16, 2014 6:40 AM, "Herbert Valerio Riedel" wrote: >> >>> >>> The Proposal >>> ============ >>> >>> I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in >>> order to add Generics support to the `NFData` class based on the >>> `-XDeriveGenerics` and `-XDefaultSignature` language extensions. >>> >>> A concrete patch is available for bike-review at [3] >>> >>> >>> Prior Proposal & What's changed >>> =============================== >>> >>> About 2 years ago, I already proposed something similar[4]. Back then >>> the major concern was avoiding a conditionally exported API as using the >>> (back then) rather young `Generics` extension would leave the Haskell98 >>> domain. >>> >>> This lead to me release Generics support as a companion package[2] which >>> turns out to have become a rather popular package (judging from the >>> Hackage download-count stats). >>> >>> I only realized after the discussion was effectively finished, that >>> having a separate `deepseq-generics` actually does have an IMO >>> non-neglectable downside: >>> >>> You can't support a `DefaultSignature`-based default implementation, >>> as those need to be backed into the `NFData` class. >>> >>> Missing out on `DefaultSignature` would be a shame IMO, because >>> >>> * There's a chance that starting with GHC 7.10 `deriving` may work for >>> arbitrary classes[5], putting `NFData` on equal footing as built-in >>> classes such as `Eq` or `Show`. Specifically, you would be able to >>> write >>> >>> data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char) >>> deriving (Show, Generic, NFData) >>> >>> instead of having to manually write the following boilerplate >>> >>> instance NFData Foo where >>> rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z >>> rnf (Bar x) = rnf x >>> >>> which gets tedious rather soon if you have many (and more complex) >>> types and tend to refactor regularly (with a risk of failing to adapt >>> your manual instances if you change the strictness of fields) >>> >>> >>> * The current default `rnf` implementation, i.e. >>> >>> rnf a = a `seq` () >>> >>> is rather error-prone, as it's *very* easy to end up with an >>> incorrect instance. Especially after refactoring a type for which the >>> NF=WHNF assumption was broken after refactoring by adding new fields, >>> or changing the strictness of existing fields. >>> >>> The Generics-derived `rnf` implementation does not have such a >>> problem. >>> >>> >>> Moreover, popular packages are starting adopt (and even recommend) the >>> use of Generics in combination with `DefaultSignature` to provide >>> automatically derived default instances, most notably `hashable`[6], >>> `binary`[7], or `aeson`[8] just to name a few. In addition to providing >>> a precedence for the use of Generics, I consider those packages evidence >>> for Generics to have proven itself to the point of replacing >>> TemplateHaskell in these use-cases. >>> >>> >>> Compatibility & Breakage Considerations >>> ======================================= >>> >>> * This change requires a major version bump to deepseq-1.4.0 >>> >>> * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first >>> version to support Generics & `DefaultSignature`. >>> >>> * Code relying on the current `rnf` default-implementation will most >>> likely break (unless a `Generics` instance happens to be in-place) >>> >>> However, it's easy to provide forward/backward-compatibility w/o any >>> CPP, by simply explicitly defining >>> >>> instance NFData XYZ where rnf = seq x () >>> >>> >>> >>> Discussion Period: 2 weeks >>> >>> >>> >>> [1]: http://hackage.haskell.org/package/deepseq >>> [2]: http://hackage.haskell.org/package/deepseq-generics >>> [3]: https://github.com/haskell/deepseq/pull/1 >>> [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940 >>> [5]: https://ghc.haskell.org/trac/ghc/ticket/5462 >>> [6]: http://hackage.haskell.org/package/hashable >>> [7]: http://hackage.haskell.org/package/binary >>> [8]: http://hackage.haskell.org/package/aeson >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://www.haskell.org/mailman/listinfo/libraries >>> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dreixel at gmail.com Thu Oct 16 14:39:11 2014 From: dreixel at gmail.com (=?UTF-8?Q?Jos=C3=A9_Pedro_Magalh=C3=A3es?=) Date: Thu, 16 Oct 2014 15:39:11 +0100 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: References: <87h9z4wb5t.fsf@gnu.org> Message-ID: I'd like to know exactly what is the important problem, and how DefaultSignatures are insufficiently general. Perhaps we can improve them, or come up with something better! On Thu, Oct 16, 2014 at 2:36 PM, David Feuer wrote: > I'm generally opposed to DefaultSignatures as an upside-down, > insufficiently-general attempt to solve an important problem, and generally > think the less relies on them the better. > On Oct 16, 2014 6:40 AM, "Herbert Valerio Riedel" wrote: > >> >> The Proposal >> ============ >> >> I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in >> order to add Generics support to the `NFData` class based on the >> `-XDeriveGenerics` and `-XDefaultSignature` language extensions. >> >> A concrete patch is available for bike-review at [3] >> >> >> Prior Proposal & What's changed >> =============================== >> >> About 2 years ago, I already proposed something similar[4]. Back then >> the major concern was avoiding a conditionally exported API as using the >> (back then) rather young `Generics` extension would leave the Haskell98 >> domain. >> >> This lead to me release Generics support as a companion package[2] which >> turns out to have become a rather popular package (judging from the >> Hackage download-count stats). >> >> I only realized after the discussion was effectively finished, that >> having a separate `deepseq-generics` actually does have an IMO >> non-neglectable downside: >> >> You can't support a `DefaultSignature`-based default implementation, >> as those need to be backed into the `NFData` class. >> >> Missing out on `DefaultSignature` would be a shame IMO, because >> >> * There's a chance that starting with GHC 7.10 `deriving` may work for >> arbitrary classes[5], putting `NFData` on equal footing as built-in >> classes such as `Eq` or `Show`. Specifically, you would be able to >> write >> >> data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char) >> deriving (Show, Generic, NFData) >> >> instead of having to manually write the following boilerplate >> >> instance NFData Foo where >> rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z >> rnf (Bar x) = rnf x >> >> which gets tedious rather soon if you have many (and more complex) >> types and tend to refactor regularly (with a risk of failing to adapt >> your manual instances if you change the strictness of fields) >> >> >> * The current default `rnf` implementation, i.e. >> >> rnf a = a `seq` () >> >> is rather error-prone, as it's *very* easy to end up with an >> incorrect instance. Especially after refactoring a type for which the >> NF=WHNF assumption was broken after refactoring by adding new fields, >> or changing the strictness of existing fields. >> >> The Generics-derived `rnf` implementation does not have such a >> problem. >> >> >> Moreover, popular packages are starting adopt (and even recommend) the >> use of Generics in combination with `DefaultSignature` to provide >> automatically derived default instances, most notably `hashable`[6], >> `binary`[7], or `aeson`[8] just to name a few. In addition to providing >> a precedence for the use of Generics, I consider those packages evidence >> for Generics to have proven itself to the point of replacing >> TemplateHaskell in these use-cases. >> >> >> Compatibility & Breakage Considerations >> ======================================= >> >> * This change requires a major version bump to deepseq-1.4.0 >> >> * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first >> version to support Generics & `DefaultSignature`. >> >> * Code relying on the current `rnf` default-implementation will most >> likely break (unless a `Generics` instance happens to be in-place) >> >> However, it's easy to provide forward/backward-compatibility w/o any >> CPP, by simply explicitly defining >> >> instance NFData XYZ where rnf = seq x () >> >> >> >> Discussion Period: 2 weeks >> >> >> >> [1]: http://hackage.haskell.org/package/deepseq >> [2]: http://hackage.haskell.org/package/deepseq-generics >> [3]: https://github.com/haskell/deepseq/pull/1 >> [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940 >> [5]: https://ghc.haskell.org/trac/ghc/ticket/5462 >> [6]: http://hackage.haskell.org/package/hashable >> [7]: http://hackage.haskell.org/package/binary >> [8]: http://hackage.haskell.org/package/aeson >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Thu Oct 16 15:03:46 2014 From: david.feuer at gmail.com (David Feuer) Date: Thu, 16 Oct 2014 11:03:46 -0400 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: References: <87h9z4wb5t.fsf@gnu.org> Message-ID: The important problem, as Edward Kmett would put it, is that Haskell is not good at dealing with lots of abstractions. In particular, making the typeclass hierarchy too fine-grained makes it painful to work with, because programmers have to satisfy the tower of superclass constraints in order to write an instance for a class. DefaultSignatures addresses this in a very limited way: If A a => B a => C a => D a then I may be able to give A, B, and C methods defaults with signatures so that I can declare an instance of D without needing to declare all the superclass instances. Unfortunately, this breaks down as soon as things branch: A a => B a => C a => D a || V E a => F a => G a Both E and B may offer perfectly reasonable default definitions of a method in A, but I can only choose *one* of them. It also fails when class A is in someone else's module, and I'm doing a ton of work with subclasses of B and would like very much to add a default definition of a method in A, but simply can't. The current common use of DefaultSignatures is to use it *only* to provide defaults for Generic instances. While this single use-case works reasonably well, it effectively privileges Generic over everything else and leaves the general problem unsolved. The sort of general solution I'd hope for would probably look something vaguely like this, but I imagine the type gurus might see problems: Allow a *subclass* of a class to define (and override) default methods for the superclass. There is, of course, an immediate challenge: a single type could be a member of two subclasses, each of which defines a default for the same superclass method. The best solution I can think of to this is to require that such incoherent defaults be resolved manually by giving an explicit superclass instance declaration; ideally, that declaration would be able to access and choose from one of the available defaults, but that might be more trouble than it's worth. On Thu, Oct 16, 2014 at 10:39 AM, Jos? Pedro Magalh?es wrote: > I'd like to know exactly what is the important problem, and how > DefaultSignatures are insufficiently general. Perhaps we can improve them, > or come up with something better! > > On Thu, Oct 16, 2014 at 2:36 PM, David Feuer > wrote: > >> I'm generally opposed to DefaultSignatures as an upside-down, >> insufficiently-general attempt to solve an important problem, and generally >> think the less relies on them the better. >> On Oct 16, 2014 6:40 AM, "Herbert Valerio Riedel" wrote: >> >>> >>> The Proposal >>> ============ >>> >>> I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in >>> order to add Generics support to the `NFData` class based on the >>> `-XDeriveGenerics` and `-XDefaultSignature` language extensions. >>> >>> A concrete patch is available for bike-review at [3] >>> >>> >>> Prior Proposal & What's changed >>> =============================== >>> >>> About 2 years ago, I already proposed something similar[4]. Back then >>> the major concern was avoiding a conditionally exported API as using the >>> (back then) rather young `Generics` extension would leave the Haskell98 >>> domain. >>> >>> This lead to me release Generics support as a companion package[2] which >>> turns out to have become a rather popular package (judging from the >>> Hackage download-count stats). >>> >>> I only realized after the discussion was effectively finished, that >>> having a separate `deepseq-generics` actually does have an IMO >>> non-neglectable downside: >>> >>> You can't support a `DefaultSignature`-based default implementation, >>> as those need to be backed into the `NFData` class. >>> >>> Missing out on `DefaultSignature` would be a shame IMO, because >>> >>> * There's a chance that starting with GHC 7.10 `deriving` may work for >>> arbitrary classes[5], putting `NFData` on equal footing as built-in >>> classes such as `Eq` or `Show`. Specifically, you would be able to >>> write >>> >>> data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char) >>> deriving (Show, Generic, NFData) >>> >>> instead of having to manually write the following boilerplate >>> >>> instance NFData Foo where >>> rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z >>> rnf (Bar x) = rnf x >>> >>> which gets tedious rather soon if you have many (and more complex) >>> types and tend to refactor regularly (with a risk of failing to adapt >>> your manual instances if you change the strictness of fields) >>> >>> >>> * The current default `rnf` implementation, i.e. >>> >>> rnf a = a `seq` () >>> >>> is rather error-prone, as it's *very* easy to end up with an >>> incorrect instance. Especially after refactoring a type for which the >>> NF=WHNF assumption was broken after refactoring by adding new fields, >>> or changing the strictness of existing fields. >>> >>> The Generics-derived `rnf` implementation does not have such a >>> problem. >>> >>> >>> Moreover, popular packages are starting adopt (and even recommend) the >>> use of Generics in combination with `DefaultSignature` to provide >>> automatically derived default instances, most notably `hashable`[6], >>> `binary`[7], or `aeson`[8] just to name a few. In addition to providing >>> a precedence for the use of Generics, I consider those packages evidence >>> for Generics to have proven itself to the point of replacing >>> TemplateHaskell in these use-cases. >>> >>> >>> Compatibility & Breakage Considerations >>> ======================================= >>> >>> * This change requires a major version bump to deepseq-1.4.0 >>> >>> * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first >>> version to support Generics & `DefaultSignature`. >>> >>> * Code relying on the current `rnf` default-implementation will most >>> likely break (unless a `Generics` instance happens to be in-place) >>> >>> However, it's easy to provide forward/backward-compatibility w/o any >>> CPP, by simply explicitly defining >>> >>> instance NFData XYZ where rnf = seq x () >>> >>> >>> >>> Discussion Period: 2 weeks >>> >>> >>> >>> [1]: http://hackage.haskell.org/package/deepseq >>> [2]: http://hackage.haskell.org/package/deepseq-generics >>> [3]: https://github.com/haskell/deepseq/pull/1 >>> [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940 >>> [5]: https://ghc.haskell.org/trac/ghc/ticket/5462 >>> [6]: http://hackage.haskell.org/package/hashable >>> [7]: http://hackage.haskell.org/package/binary >>> [8]: http://hackage.haskell.org/package/aeson >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://www.haskell.org/mailman/listinfo/libraries >>> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From johan.tibell at gmail.com Thu Oct 16 15:12:50 2014 From: johan.tibell at gmail.com (Johan Tibell) Date: Thu, 16 Oct 2014 17:12:50 +0200 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: References: <87h9z4wb5t.fsf@gnu.org> Message-ID: Thanks for the clarification. I'd encourage you to start a separate discussion for coming up with a design for something better. Lets leave this thread for the smaller technical issue of merging an already well-liked extension (which I think is the best we can do in current Haskell) back into its main package. On Thu, Oct 16, 2014 at 5:03 PM, David Feuer wrote: > The important problem, as Edward Kmett would put it, is that Haskell is > not good at dealing with lots of abstractions. In particular, making the > typeclass hierarchy too fine-grained makes it painful to work with, because > programmers have to satisfy the tower of superclass constraints in order to > write an instance for a class. DefaultSignatures addresses this in a very > limited way: If > > A a => B a => C a => D a > > then I may be able to give A, B, and C methods defaults with signatures so > that I can declare an instance of D without needing to declare all the > superclass instances. Unfortunately, this breaks down as soon as things > branch: > > A a => B a => C a => D a > > || > V > > E a => F a => G a > > Both E and B may offer perfectly reasonable default definitions of a > method in A, but I can only choose *one* of them. It also fails when class > A is in someone else's module, and I'm doing a ton of work with subclasses > of B and would like very much to add a default definition of a method in A, > but simply can't. The current common use of DefaultSignatures is to use it > *only* to provide defaults for Generic instances. While this single > use-case works reasonably well, it effectively privileges Generic over > everything else and leaves the general problem unsolved. > > The sort of general solution I'd hope for would probably look something > vaguely like this, but I imagine the type gurus might see problems: > > Allow a *subclass* of a class to define (and override) default methods for > the superclass. There is, of course, an immediate challenge: a single type > could be a member of two subclasses, each of which defines a default for > the same superclass method. The best solution I can think of to this is to > require that such incoherent defaults be resolved manually by giving an > explicit superclass instance declaration; ideally, that declaration would > be able to access and choose from one of the available defaults, but that > might be more trouble than it's worth. > > On Thu, Oct 16, 2014 at 10:39 AM, Jos? Pedro Magalh?es > wrote: > >> I'd like to know exactly what is the important problem, and how >> DefaultSignatures are insufficiently general. Perhaps we can improve them, >> or come up with something better! >> >> On Thu, Oct 16, 2014 at 2:36 PM, David Feuer >> wrote: >> >>> I'm generally opposed to DefaultSignatures as an upside-down, >>> insufficiently-general attempt to solve an important problem, and generally >>> think the less relies on them the better. >>> On Oct 16, 2014 6:40 AM, "Herbert Valerio Riedel" wrote: >>> >>>> >>>> The Proposal >>>> ============ >>>> >>>> I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in >>>> order to add Generics support to the `NFData` class based on the >>>> `-XDeriveGenerics` and `-XDefaultSignature` language extensions. >>>> >>>> A concrete patch is available for bike-review at [3] >>>> >>>> >>>> Prior Proposal & What's changed >>>> =============================== >>>> >>>> About 2 years ago, I already proposed something similar[4]. Back then >>>> the major concern was avoiding a conditionally exported API as using the >>>> (back then) rather young `Generics` extension would leave the Haskell98 >>>> domain. >>>> >>>> This lead to me release Generics support as a companion package[2] which >>>> turns out to have become a rather popular package (judging from the >>>> Hackage download-count stats). >>>> >>>> I only realized after the discussion was effectively finished, that >>>> having a separate `deepseq-generics` actually does have an IMO >>>> non-neglectable downside: >>>> >>>> You can't support a `DefaultSignature`-based default implementation, >>>> as those need to be backed into the `NFData` class. >>>> >>>> Missing out on `DefaultSignature` would be a shame IMO, because >>>> >>>> * There's a chance that starting with GHC 7.10 `deriving` may work for >>>> arbitrary classes[5], putting `NFData` on equal footing as built-in >>>> classes such as `Eq` or `Show`. Specifically, you would be able to >>>> write >>>> >>>> data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char) >>>> deriving (Show, Generic, NFData) >>>> >>>> instead of having to manually write the following boilerplate >>>> >>>> instance NFData Foo where >>>> rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z >>>> rnf (Bar x) = rnf x >>>> >>>> which gets tedious rather soon if you have many (and more complex) >>>> types and tend to refactor regularly (with a risk of failing to adapt >>>> your manual instances if you change the strictness of fields) >>>> >>>> >>>> * The current default `rnf` implementation, i.e. >>>> >>>> rnf a = a `seq` () >>>> >>>> is rather error-prone, as it's *very* easy to end up with an >>>> incorrect instance. Especially after refactoring a type for which the >>>> NF=WHNF assumption was broken after refactoring by adding new fields, >>>> or changing the strictness of existing fields. >>>> >>>> The Generics-derived `rnf` implementation does not have such a >>>> problem. >>>> >>>> >>>> Moreover, popular packages are starting adopt (and even recommend) the >>>> use of Generics in combination with `DefaultSignature` to provide >>>> automatically derived default instances, most notably `hashable`[6], >>>> `binary`[7], or `aeson`[8] just to name a few. In addition to providing >>>> a precedence for the use of Generics, I consider those packages evidence >>>> for Generics to have proven itself to the point of replacing >>>> TemplateHaskell in these use-cases. >>>> >>>> >>>> Compatibility & Breakage Considerations >>>> ======================================= >>>> >>>> * This change requires a major version bump to deepseq-1.4.0 >>>> >>>> * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first >>>> version to support Generics & `DefaultSignature`. >>>> >>>> * Code relying on the current `rnf` default-implementation will most >>>> likely break (unless a `Generics` instance happens to be in-place) >>>> >>>> However, it's easy to provide forward/backward-compatibility w/o any >>>> CPP, by simply explicitly defining >>>> >>>> instance NFData XYZ where rnf = seq x () >>>> >>>> >>>> >>>> Discussion Period: 2 weeks >>>> >>>> >>>> >>>> [1]: http://hackage.haskell.org/package/deepseq >>>> [2]: http://hackage.haskell.org/package/deepseq-generics >>>> [3]: https://github.com/haskell/deepseq/pull/1 >>>> [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940 >>>> [5]: https://ghc.haskell.org/trac/ghc/ticket/5462 >>>> [6]: http://hackage.haskell.org/package/hashable >>>> [7]: http://hackage.haskell.org/package/binary >>>> [8]: http://hackage.haskell.org/package/aeson >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://www.haskell.org/mailman/listinfo/libraries >>>> >>> >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://www.haskell.org/mailman/listinfo/libraries >>> >>> >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From hesselink at gmail.com Thu Oct 16 15:30:36 2014 From: hesselink at gmail.com (Erik Hesselink) Date: Thu, 16 Oct 2014 17:30:36 +0200 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: References: <87h9z4wb5t.fsf@gnu.org> Message-ID: This reminds me of the default superclass instances proposals that people are working on. I found three different ones on the GHC trac [1,2,3]. Erik [1] https://ghc.haskell.org/trac/ghc/wiki/DefaultSuperclassInstances [2] https://ghc.haskell.org/trac/ghc/wiki/IntrinsicSuperclasses [3] https://ghc.haskell.org/trac/ghc/wiki/InstanceTemplates On Thu, Oct 16, 2014 at 5:03 PM, David Feuer wrote: > The important problem, as Edward Kmett would put it, is that Haskell is not > good at dealing with lots of abstractions. In particular, making the > typeclass hierarchy too fine-grained makes it painful to work with, because > programmers have to satisfy the tower of superclass constraints in order to > write an instance for a class. DefaultSignatures addresses this in a very > limited way: If > > A a => B a => C a => D a > > then I may be able to give A, B, and C methods defaults with signatures so > that I can declare an instance of D without needing to declare all the > superclass instances. Unfortunately, this breaks down as soon as things > branch: > > A a => B a => C a => D a > > || > V > > E a => F a => G a > > Both E and B may offer perfectly reasonable default definitions of a method > in A, but I can only choose *one* of them. It also fails when class A is in > someone else's module, and I'm doing a ton of work with subclasses of B and > would like very much to add a default definition of a method in A, but > simply can't. The current common use of DefaultSignatures is to use it > *only* to provide defaults for Generic instances. While this single use-case > works reasonably well, it effectively privileges Generic over everything > else and leaves the general problem unsolved. > > The sort of general solution I'd hope for would probably look something > vaguely like this, but I imagine the type gurus might see problems: > > Allow a *subclass* of a class to define (and override) default methods for > the superclass. There is, of course, an immediate challenge: a single type > could be a member of two subclasses, each of which defines a default for the > same superclass method. The best solution I can think of to this is to > require that such incoherent defaults be resolved manually by giving an > explicit superclass instance declaration; ideally, that declaration would be > able to access and choose from one of the available defaults, but that might > be more trouble than it's worth. > > On Thu, Oct 16, 2014 at 10:39 AM, Jos? Pedro Magalh?es > wrote: >> >> I'd like to know exactly what is the important problem, and how >> DefaultSignatures are insufficiently general. Perhaps we can improve them, >> or come up with something better! >> >> On Thu, Oct 16, 2014 at 2:36 PM, David Feuer >> wrote: >>> >>> I'm generally opposed to DefaultSignatures as an upside-down, >>> insufficiently-general attempt to solve an important problem, and generally >>> think the less relies on them the better. >>> >>> On Oct 16, 2014 6:40 AM, "Herbert Valerio Riedel" wrote: >>>> >>>> >>>> The Proposal >>>> ============ >>>> >>>> I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in >>>> order to add Generics support to the `NFData` class based on the >>>> `-XDeriveGenerics` and `-XDefaultSignature` language extensions. >>>> >>>> A concrete patch is available for bike-review at [3] >>>> >>>> >>>> Prior Proposal & What's changed >>>> =============================== >>>> >>>> About 2 years ago, I already proposed something similar[4]. Back then >>>> the major concern was avoiding a conditionally exported API as using the >>>> (back then) rather young `Generics` extension would leave the Haskell98 >>>> domain. >>>> >>>> This lead to me release Generics support as a companion package[2] which >>>> turns out to have become a rather popular package (judging from the >>>> Hackage download-count stats). >>>> >>>> I only realized after the discussion was effectively finished, that >>>> having a separate `deepseq-generics` actually does have an IMO >>>> non-neglectable downside: >>>> >>>> You can't support a `DefaultSignature`-based default implementation, >>>> as those need to be backed into the `NFData` class. >>>> >>>> Missing out on `DefaultSignature` would be a shame IMO, because >>>> >>>> * There's a chance that starting with GHC 7.10 `deriving` may work for >>>> arbitrary classes[5], putting `NFData` on equal footing as built-in >>>> classes such as `Eq` or `Show`. Specifically, you would be able to >>>> write >>>> >>>> data Foo = Foo [Int] String (Bool,Char) | Bar (Maybe Char) >>>> deriving (Show, Generic, NFData) >>>> >>>> instead of having to manually write the following boilerplate >>>> >>>> instance NFData Foo where >>>> rnf (Foo x y z) = rnf x `seq` rnf y `seq` rnf z >>>> rnf (Bar x) = rnf x >>>> >>>> which gets tedious rather soon if you have many (and more complex) >>>> types and tend to refactor regularly (with a risk of failing to adapt >>>> your manual instances if you change the strictness of fields) >>>> >>>> >>>> * The current default `rnf` implementation, i.e. >>>> >>>> rnf a = a `seq` () >>>> >>>> is rather error-prone, as it's *very* easy to end up with an >>>> incorrect instance. Especially after refactoring a type for which the >>>> NF=WHNF assumption was broken after refactoring by adding new fields, >>>> or changing the strictness of existing fields. >>>> >>>> The Generics-derived `rnf` implementation does not have such a >>>> problem. >>>> >>>> >>>> Moreover, popular packages are starting adopt (and even recommend) the >>>> use of Generics in combination with `DefaultSignature` to provide >>>> automatically derived default instances, most notably `hashable`[6], >>>> `binary`[7], or `aeson`[8] just to name a few. In addition to providing >>>> a precedence for the use of Generics, I consider those packages evidence >>>> for Generics to have proven itself to the point of replacing >>>> TemplateHaskell in these use-cases. >>>> >>>> >>>> Compatibility & Breakage Considerations >>>> ======================================= >>>> >>>> * This change requires a major version bump to deepseq-1.4.0 >>>> >>>> * `deepseq` needs to drop GHC 7.0.* support as GHC 7.2 is the first >>>> version to support Generics & `DefaultSignature`. >>>> >>>> * Code relying on the current `rnf` default-implementation will most >>>> likely break (unless a `Generics` instance happens to be in-place) >>>> >>>> However, it's easy to provide forward/backward-compatibility w/o any >>>> CPP, by simply explicitly defining >>>> >>>> instance NFData XYZ where rnf = seq x () >>>> >>>> >>>> >>>> Discussion Period: 2 weeks >>>> >>>> >>>> >>>> [1]: http://hackage.haskell.org/package/deepseq >>>> [2]: http://hackage.haskell.org/package/deepseq-generics >>>> [3]: https://github.com/haskell/deepseq/pull/1 >>>> [4]: http://thread.gmane.org/gmane.comp.lang.haskell.libraries/17940 >>>> [5]: https://ghc.haskell.org/trac/ghc/ticket/5462 >>>> [6]: http://hackage.haskell.org/package/hashable >>>> [7]: http://hackage.haskell.org/package/binary >>>> [8]: http://hackage.haskell.org/package/aeson >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://www.haskell.org/mailman/listinfo/libraries >>> >>> >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://www.haskell.org/mailman/listinfo/libraries >>> >> > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > From andres.loeh at gmail.com Thu Oct 16 17:09:08 2014 From: andres.loeh at gmail.com (=?UTF-8?Q?Andres_L=C3=B6h?=) Date: Thu, 16 Oct 2014 19:09:08 +0200 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: <87h9z4wb5t.fsf@gnu.org> References: <87h9z4wb5t.fsf@gnu.org> Message-ID: > The Proposal > ============ > > I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in > order to add Generics support to the `NFData` class based on the > `-XDeriveGenerics` and `-XDefaultSignature` language extensions. > > A concrete patch is available for bike-review at [3] +1 Cheers, Andres From david.feuer at gmail.com Thu Oct 16 17:14:08 2014 From: david.feuer at gmail.com (David Feuer) Date: Thu, 16 Oct 2014 13:14:08 -0400 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List Message-ID: These functions can be lifted pretty much straight out of Data.Sequence. In particular, foldrWithIndex makes for a particularly nice expression of a fusing findIndices function, as is present in Data.Sequence. -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Thu Oct 16 17:21:35 2014 From: david.feuer at gmail.com (David Feuer) Date: Thu, 16 Oct 2014 13:21:35 -0400 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: References: Message-ID: Actually, that proposal is firmly in the past. Let's *move* foldrWithIndex and foldlWithIndex from Data.Sequence to Data.Foldable! On Thu, Oct 16, 2014 at 1:14 PM, David Feuer wrote: > These functions can be lifted pretty much straight out of Data.Sequence. > In particular, foldrWithIndex makes for a particularly nice expression of a > fusing findIndices function, as is present in Data.Sequence. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Thu Oct 16 19:31:57 2014 From: ekmett at gmail.com (Edward Kmett) Date: Thu, 16 Oct 2014 15:31:57 -0400 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: References: Message-ID: I'm a pretty strong -1 on moving foldrWithIndex into Data.Foldable. Why? The only index Foldable can provide is an ordinal index starting at 0. The one folks _expect_ in many cases from Map k, IntMap and the like is the key. This introduces a huge source of potential confusion and new name conflicts for marginal benefit. -Edward On Thu, Oct 16, 2014 at 1:21 PM, David Feuer wrote: > Actually, that proposal is firmly in the past. Let's *move* foldrWithIndex > and foldlWithIndex from Data.Sequence to Data.Foldable! > > On Thu, Oct 16, 2014 at 1:14 PM, David Feuer > wrote: > >> These functions can be lifted pretty much straight out of Data.Sequence. >> In particular, foldrWithIndex makes for a particularly nice expression of a >> fusing findIndices function, as is present in Data.Sequence. >> > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Thu Oct 16 19:41:27 2014 From: ekmett at gmail.com (Edward Kmett) Date: Thu, 16 Oct 2014 15:41:27 -0400 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: References: <87h9z4wb5t.fsf@gnu.org> Message-ID: On one hand, the change is a path to a better deepseq that is more correct. On the other hand 1.) It does change the semantics of existing code. 2.) It does cause existing code that works to break if they don't supply a Generic instance or a manual default. Admittedly: #1 happens by making it more strict, which is what we want in the case of NFData, for once. #2 is something that is easily rectified and makes the resulting code more robust/useful anyways. Folks who don't want to lean on generics have the option to just write the rnf x = seq x () default, so nobody is being forced to lean on the extension. I'm somewhat on the fence about this, because I don't like silent semantics changes, but as it is only happening by making things more strict *in the one place in the language* where that is the very point, you can consider me weakly +1. -Edward On Thu, Oct 16, 2014 at 1:09 PM, Andres L?h wrote: > > The Proposal > > ============ > > > > I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in > > order to add Generics support to the `NFData` class based on the > > `-XDeriveGenerics` and `-XDefaultSignature` language extensions. > > > > A concrete patch is available for bike-review at [3] > > +1 > > Cheers, > Andres > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexander at plaimi.net Fri Oct 17 07:16:40 2014 From: alexander at plaimi.net (Alexander Berntsen) Date: Fri, 17 Oct 2014 09:16:40 +0200 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: References: Message-ID: <5440C258.4020807@plaimi.net> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 On 16/10/14 21:31, Edward Kmett wrote: > -1 on moving foldrWithIndex into Data.Foldable. - -1 here too. 0 on moving it to Data.List. Not sure there's any benefit. - -- Alexander alexander at plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iF4EAREIAAYFAlRAwlgACgkQRtClrXBQc7XE9wD8DFB1uYmBqUq2GPXv0zq3F1BS I3FFKdQqbp7/mWpjxwgBAKQ/19mF4kDci0D8godYWzBRttMnIz0LqUJzecm78+6d =YCzV -----END PGP SIGNATURE----- From twanvl at gmail.com Fri Oct 17 11:41:17 2014 From: twanvl at gmail.com (Twan van Laarhoven) Date: Fri, 17 Oct 2014 13:41:17 +0200 Subject: Proposal: Improve error messages for (!!) (include index and length of list) In-Reply-To: References: <20141016030239.GA25378@x200> <87d29sw83i.fsf@gnu.org> Message-ID: <5441005D.8090609@gmail.com> You don't need an extra parameter for calculating the length, because len = n - idx So, xs !! (I# n) = go xs n where go [] idx = error $ "... Index " ++ show (I# n) ++ " too large for list of length" ++ show (I# (n -# idx)) go (x:_) 0# = x go (_:xs) idx = go xs (idx +# 1) By the way, do we still need all the manual unboxing with a modern Ghc? Twan On 2014-10-16 14:13, Thomas Schilling wrote: > Yes, you'd have to calculate the length on the fly. i.e., something > like this (untested): > > xs !! n | n < 0 = error "... negative index ..." > xs !! (I# n) = go xs n 0# > where > go [] idx len = error $ "... Index " ++ show (I# (idx +# len) ++ " > too large for list of length " > ++ show (I# len) > go (x:_) 0# _ = x > go (_:xs) idx len = go xs (idx -# 0#) (len +# 1#) > > On modern processors the extra addition and the extra parameter > shouldn't hurt, though we'd need a benchmark to make sure, of course. > You could also make the error message a bit less helpful and just > return how far the index pointed past the end of the list. > > > On 16 October 2014 13:46, Herbert Valerio Riedel wrote: >> On 2014-10-16 at 08:20:55 +0200, Simon Hengel wrote: >> >> [...] >> >>> I propose to change the error messages for the non-report version to >>> include index and list length, something that is functionally equivalent >>> to: >> >> While I'm very sympathetic to better error messages; doesn't the >> implementation you gave defer garbage-collecting the start of the list, >> by keeping the head of the list alive until either the desired index has >> been reached or end-of-list is detected? >> >> e.g. consider something (silly) like ([1..] !! 10000000) >> >> Cheers, >> hvr >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > From nominolo at googlemail.com Fri Oct 17 12:32:25 2014 From: nominolo at googlemail.com (Thomas Schilling) Date: Fri, 17 Oct 2014 14:32:25 +0200 Subject: Proposal: Improve error messages for (!!) (include index and length of list) In-Reply-To: <5441005D.8090609@gmail.com> References: <20141016030239.GA25378@x200> <87d29sw83i.fsf@gnu.org> <5441005D.8090609@gmail.com> Message-ID: Well, it still needs to remember the value of the initial index somewhere, but in this case it puts it on the stack. This version is indeed faster than the one that computes. This seems to cost 4-5 ns for short lists. Interestingly, this version seems to sometimes be a bit faster for longer lists, but that's probably not what we should optimise for. Benchmarks below. {-# LANGUAGE MagicHash #-} module Main where import Criterion.Main import GHC.Exts (Int(..), (+#), (-#)) nth1 :: [a] -> Int -> a nth1 ys n | n < 0 = error $ "Prelude.(!!): negative index " ++ show n nth1 ys (I# i) = go ys i where go (x:_) 0# = x go (_:xs) idx = go xs (idx -# 1#) go [] idx = error $ "Prelude.(!!): index " ++ show (I# i) ++ " too large for list of length " ++ show (I# (i -# idx)) nth2 :: [a] -> Int -> a nth2 ys n | n < 0 = error $ "Prelude.(!!): negative index " ++ show n nth2 ys (I# i) = go ys i 0# where go (x:_) 0# _len = x go (_:xs) idx len = go xs (idx -# 1#) (len +# 1#) go [] idx len = error $ "Prelude.(!!): index " ++ show (I# (idx +# len)) ++ " too large for list of length " ++ show (I# len) main = do let l1 = [1..5] let l2 = [1..500] defaultMain [ bgroup "nth" [ bench "3/old" $ whnf (l1 !!) 3 , bench "3/new/let-no-escape" $ whnf (l1 `nth1`) 3 , bench "3/new/more-compute" $ whnf (l1 `nth2`) 3 , bench "300/old" $ whnf (l2 !!) 300 , bench "300/new/let-no-escape" $ whnf (l2 `nth1`) 300 , bench "300/new/more-compute" $ whnf (l2 `nth2`) 300 ] ] benchmarking nth/3/old time 44.30 ns (43.94 ns .. 44.65 ns) 1.000 R? (0.999 R? .. 1.000 R?) mean 44.24 ns (43.99 ns .. 44.58 ns) std dev 1.001 ns (837.9 ps .. 1.221 ns) variance introduced by outliers: 34% (moderately inflated) benchmarking nth/3/new/let-no-escape time 51.68 ns (51.36 ns .. 52.01 ns) 1.000 R? (0.999 R? .. 1.000 R?) mean 51.70 ns (51.38 ns .. 52.05 ns) std dev 1.146 ns (922.3 ps .. 1.495 ns) variance introduced by outliers: 33% (moderately inflated) benchmarking nth/3/new/more-compute time 53.44 ns (53.12 ns .. 53.77 ns) 1.000 R? (0.999 R? .. 1.000 R?) mean 53.55 ns (53.16 ns .. 54.12 ns) std dev 1.591 ns (1.089 ns .. 2.354 ns) variance introduced by outliers: 47% (moderately inflated) benchmarking nth/300/old time 747.4 ns (740.7 ns .. 753.6 ns) 0.999 R? (0.999 R? .. 1.000 R?) mean 742.9 ns (737.1 ns .. 751.4 ns) std dev 23.00 ns (17.75 ns .. 33.61 ns) variance introduced by outliers: 43% (moderately inflated) benchmarking nth/300/new/let-no-escape time 742.7 ns (736.7 ns .. 749.2 ns) 0.999 R? (0.999 R? .. 1.000 R?) mean 745.1 ns (738.8 ns .. 757.8 ns) std dev 28.11 ns (19.71 ns .. 42.69 ns) variance introduced by outliers: 53% (severely inflated) benchmarking nth/300/new/more-compute time 810.2 ns (801.5 ns .. 818.3 ns) 0.999 R? (0.999 R? .. 0.999 R?) mean 812.9 ns (804.4 ns .. 824.5 ns) std dev 33.12 ns (25.91 ns .. 43.59 ns) variance introduced by outliers: 57% (severely inflated) On 17 October 2014 13:41, Twan van Laarhoven wrote: > You don't need an extra parameter for calculating the length, because > len = n - idx > So, > > xs !! (I# n) = go xs n > where > go [] idx = error $ "... Index " ++ show (I# n) > ++ " too large for list of length" ++ show (I# (n -# idx)) > go (x:_) 0# = x > go (_:xs) idx = go xs (idx +# 1) > > By the way, do we still need all the manual unboxing with a modern Ghc? > > Twan > > > On 2014-10-16 14:13, Thomas Schilling wrote: >> >> Yes, you'd have to calculate the length on the fly. i.e., something >> like this (untested): >> >> xs !! n | n < 0 = error "... negative index ..." >> xs !! (I# n) = go xs n 0# >> where >> go [] idx len = error $ "... Index " ++ show (I# (idx +# len) ++ " >> too large for list of length " >> ++ show (I# len) >> go (x:_) 0# _ = x >> go (_:xs) idx len = go xs (idx -# 0#) (len +# 1#) >> >> On modern processors the extra addition and the extra parameter >> shouldn't hurt, though we'd need a benchmark to make sure, of course. >> You could also make the error message a bit less helpful and just >> return how far the index pointed past the end of the list. >> >> >> On 16 October 2014 13:46, Herbert Valerio Riedel wrote: >>> >>> On 2014-10-16 at 08:20:55 +0200, Simon Hengel wrote: >>> >>> [...] >>> >>>> I propose to change the error messages for the non-report version to >>>> include index and list length, something that is functionally equivalent >>>> to: >>> >>> >>> While I'm very sympathetic to better error messages; doesn't the >>> implementation you gave defer garbage-collecting the start of the list, >>> by keeping the head of the list alive until either the desired index has >>> been reached or end-of-list is detected? >>> >>> e.g. consider something (silly) like ([1..] !! 10000000) >>> >>> Cheers, >>> hvr >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://www.haskell.org/mailman/listinfo/libraries >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries From hvr at gnu.org Sun Oct 19 10:20:23 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Sun, 19 Oct 2014 12:20:23 +0200 Subject: Future of "Text.Show.Functions" module Message-ID: <87zjcs7448.fsf@gnu.org> Hello *, I noticed the following module (trimmed for brevitiy) hiding in `base`: -- This module deliberately declares orphan instances: {-# OPTIONS_GHC -fno-warn-orphans #-} -- | Optional instance of 'Text.Show.Show' for functions: -- -- > instance Show (a -> b) where -- > showsPrec _ _ = showString \"\\" -- ----------------------------------------------------------------------------- module Text.Show.Functions () where instance Show (a -> b) where showsPrec _ _ = showString "" However, I consider this a questionable module to be in `base` due to its deliberate use of orphan instances. Should this module be deprecated, removed, alternatively, should the `Show` instance be made a non-orphan (e.g. by importing it by the `Prelude` module), or shall this curiousity be just left untouched in `base` in its current form? Cheers, hvr From ndmitchell at gmail.com Sun Oct 19 12:35:02 2014 From: ndmitchell at gmail.com (Neil Mitchell) Date: Sun, 19 Oct 2014 13:35:02 +0100 Subject: FilePath modification proposal Message-ID: Hi, As maintainer, it's kind of a grey area if I need to make proposals for the filepath library, but since I'm a relatively new active maintainer for a Core library, I thought I'd err on the side of caution. Please yell if you think these are a bad idea, otherwise I'll just do them (probably over the next few weeks). * Change 1: Add -<.> as an alias for replaceExtension with the same precedence as <.> This change has been in Shake for a while now, and seems generally useful. It isn't an operator in the lens library, and it reads nicely as a combination of - (remove something) and <.> (addExtension). The argument order of replaceExtension is a bit unfortunately, since replace functions usually have the thing to replace with first, but since extensions are at the end of the FilePaths that suggests making it the second argument (which is what filepath does). In contrast, -<.> has a very obvious argument order. * Change 2: Stop testing as part of GHC The test suite is complicated enough, since it generates code from the doc comments. Having the test suite also run by GHC complicates things further, since it has to integrate with the GHC test suite environment with extra Makefiles etc. Since August 2011 the FilePath test suite actually passes even if you break the properties (oops!) so it's provided no value at all in the last 3 years. In general, running all the tests in all the places is a good thing. But I think filepath is a bit different given it's exclusively cross-platform string manipulations, so I don't think its runtime behaviour is version/platform sensitive in any way. I also develop on Windows with 4 versions of GHC, and Travis tests it on Linux with 6 versions of GHC. That seems sufficient test coverage. * Change 3: Check in the generated test code If you check out the filepath repo it won't build - you have to run some code to generate the tests first. That's a barrier to entry, and makes testing with GHC harder. I'm increasingly starting to believe that for a small number of small files where the generator ships with the code, it's easier to check in the generated code and then have Travis run the generator and check nothing changes. It's easier to get started, easier to debug when things change, and the only real cost is a few extra checkins. Thanks, Neil From haskell at ibotty.net Sun Oct 19 12:53:36 2014 From: haskell at ibotty.net (Tobias Florek) Date: Sun, 19 Oct 2014 14:53:36 +0200 Subject: FilePath modification proposal In-Reply-To: References: Message-ID: <5443B450.2030408@ibotty.net> hi, have no vote in the committee, but re > * Change 1: Add -<.> as an alias for replaceExtension with the same > precedence as <.> i am very much in favor. i have (locally) defined that or a similar alias a few times already. the other changes are imo your choice alone, as you are the (only?) person maintaining it. (i prefer not checking in auto-generated files, but... whatever.) thank you, neill, for maintaining filepath, tobias florek From michael at snoyman.com Sun Oct 19 12:59:45 2014 From: michael at snoyman.com (Michael Snoyman) Date: Sun, 19 Oct 2014 15:59:45 +0300 Subject: [core libraries] Future of "Text.Show.Functions" module In-Reply-To: <87zjcs7448.fsf@gnu.org> References: <87zjcs7448.fsf@gnu.org> Message-ID: On Sun, Oct 19, 2014 at 1:20 PM, Herbert Valerio Riedel wrote: > Hello *, > > I noticed the following module (trimmed for brevitiy) hiding in `base`: > > > -- This module deliberately declares orphan instances: > {-# OPTIONS_GHC -fno-warn-orphans #-} > > -- | Optional instance of 'Text.Show.Show' for functions: > -- > -- > instance Show (a -> b) where > -- > showsPrec _ _ = showString \"\\" > -- > > ----------------------------------------------------------------------------- > > module Text.Show.Functions () where > > instance Show (a -> b) where > showsPrec _ _ = showString "" > > > However, I consider this a questionable module to be in `base` due to > its deliberate use of orphan instances. Should this module be > deprecated, removed, alternatively, should the `Show` instance be made a > non-orphan (e.g. by importing it by the `Prelude` module), or shall this > curiousity be just left untouched in `base` in its current form? > > Cheers, > hvr > > -- > You received this message because you are subscribed to the Google Groups > "haskell-core-libraries" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to haskell-core-libraries+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > I think this really brings up the question of what `Show` should be used for. If the goal is to be simple serialization with `Read` as the inverse[1], then this is clearly a nonsense instance and shouldn't be included. If, on the other hand, we consider `Show` to be simple debug output, this makes perfect sense. Similarly, rendering `IO a` as "" or something like that makes sense too. An example where this came up recently was adding a Show instance to the Request type in WAI[2]. The goal there is explicitly debugging, and displaying some uninteresting string for any IO actions is very useful. Having such an instance built into base would have been convenient for auto-deriving of this Show instance. Overall, the problem is that we've overloaded Show in (at least) three different ways: * Textual serialization * Debugging * User-friendly display of data I think I give a +0.5 to re-exporting this instance from Prelude/making it non-orphan, since: 1. I agree that orphans in base are a bad idea. 2. Removing the instance will possibly cause breakage for someone. 3. I *do* personally lean towards using Show instances for debugging purposes, and in that context, the Show instance is a good one. Michael [1] I believe the correct term is actually a retraction. [2] https://github.com/yesodweb/wai/issues/290 -------------- next part -------------- An HTML attachment was scrubbed... URL: From hvr at gnu.org Sun Oct 19 13:18:19 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Sun, 19 Oct 2014 15:18:19 +0200 Subject: Future of "Text.Show.Functions" module In-Reply-To: <87zjcs7448.fsf@gnu.org> (Herbert Valerio Riedel's message of "Sun, 19 Oct 2014 12:20:23 +0200") References: <87zjcs7448.fsf@gnu.org> Message-ID: <87vbng6vvo.fsf@gnu.org> On 2014-10-19 at 12:20:23 +0200, Herbert Valerio Riedel wrote: [...] > instance Show (a -> b) where > showsPrec _ _ = showString "" PS: An effect of having this instance made default in Prelude is that GHCi would show a somewhat different result in some cases (not sure though if this a good or bad thing): GHCi, version 7.8.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. ?:2> id :2:1: No instance for (Show (a0 -> a0)) arising from a use of ?print? In a stmt of an interactive GHCi command: print it ?:3> import Text.Show.Functions ?:4> id it :: a -> a Cheers, hvr From lemming at henning-thielemann.de Sun Oct 19 13:19:42 2014 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Sun, 19 Oct 2014 15:19:42 +0200 (CEST) Subject: [core libraries] Future of "Text.Show.Functions" module In-Reply-To: References: <87zjcs7448.fsf@gnu.org> Message-ID: On Sun, 19 Oct 2014, Michael Snoyman wrote: > Overall, the problem is that we've overloaded Show in (at least) three different ways: > > * Textual serialization > * Debugging > * User-friendly display of data Unfortunately, the Show class is not used consistently, with the different uses you have listed. The automatically derived Show instances show valid Haskell expressions, that you can enter into GHCi in order to get back the shown value. I think we should stick to that meaning. Strictly conforming to this rule would also mean that using 'show' for formatting numbers is not precisely correct, because we cannot expect that other tools can parse all ways of writing number literals in Haskell. Maybe printf is better here, but it is unfortunately not total. Following the above rule for functions would mean, that 'show' should emit an expression that represents the function, e.g. something like Prelude> show ((\x->x*x) :: Int -> Int) fromJust . flip lookup [(0,0), (1,1), (-1,1), (2,4), (-2,4), ... From hvr at gnu.org Sun Oct 19 13:23:04 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Sun, 19 Oct 2014 15:23:04 +0200 Subject: [core libraries] Future of "Text.Show.Functions" module In-Reply-To: (Henning Thielemann's message of "Sun, 19 Oct 2014 15:19:42 +0200 (CEST)") References: <87zjcs7448.fsf@gnu.org> Message-ID: <87r3y46vnr.fsf@gnu.org> On 2014-10-19 at 15:19:42 +0200, Henning Thielemann wrote: [...] > Prelude> show ((\x->x*x) :: Int -> Int) > fromJust . flip lookup [(0,0), (1,1), (-1,1), (2,4), (-2,4), ... That scheme only works for enumerable input-types though, as computing something like 'show fmap' would be quite a challenge :-) From rwbarton at gmail.com Sun Oct 19 13:50:57 2014 From: rwbarton at gmail.com (Reid Barton) Date: Sun, 19 Oct 2014 09:50:57 -0400 Subject: Future of "Text.Show.Functions" module In-Reply-To: <87vbng6vvo.fsf@gnu.org> References: <87zjcs7448.fsf@gnu.org> <87vbng6vvo.fsf@gnu.org> Message-ID: On Sun, Oct 19, 2014 at 9:18 AM, Herbert Valerio Riedel wrote: > On 2014-10-19 at 12:20:23 +0200, Herbert Valerio Riedel wrote: > > [...] > > > instance Show (a -> b) where > > showsPrec _ _ = showString "" > > PS: An effect of having this instance made default in Prelude is that > GHCi would show a somewhat different result in some cases (not sure > though if this a good or bad thing): > > > GHCi, version 7.8.3: http://www.haskell.org/ghc/ :? for help > Loading package ghc-prim ... linking ... done. > Loading package integer-gmp ... linking ... done. > Loading package base ... linking ... done. > ?:2> id > > :2:1: > No instance for (Show (a0 -> a0)) arising from a use of ?print? > In a stmt of an interactive GHCi command: print it > ?:3> import Text.Show.Functions > ?:4> id > > it :: a -> a You seem to have ":set +t" on (show types), which isn't the default unless it changed in HEAD very recently. I'm -1 for reasons including * Worse usability in ghci by default. If I see "No instance for (Show (IOMode -> IO Handle))", I can figure out that I omitted an argument of type IOMode, but if I see "" I only know that I omitted some argument, and I have to redo the command with :t to learn more. * Precludes other instances Show (a -> b), some of which already exist in the wild, e.g. lambdabot's that uses Typeable to produce a string like " Int>" (but breaks down in the presence of polymorphism), or the 'countable' package's (Show a,Finite a,Show b) => Show (a -> b). * I don't see what we gain by forcing this instance on everybody rather than letting people opt in with "import Text.Show.Functions". When was the last time you encountered an error because two of your imports exported different Show (a -> b) instances? Orphan instances are bad in general, but for debugging hacks I think they're fine. I'm neutral on whether to remove Text.Show.Functions or leave it as is. FWIW, I was unaware of its existence before your email. Regards, Reid Barton -------------- next part -------------- An HTML attachment was scrubbed... URL: From malcolm.wallace at me.com Sun Oct 19 13:55:17 2014 From: malcolm.wallace at me.com (Malcolm Wallace) Date: Sun, 19 Oct 2014 14:55:17 +0100 Subject: Future of "Text.Show.Functions" module In-Reply-To: <87zjcs7448.fsf@gnu.org> References: <87zjcs7448.fsf@gnu.org> Message-ID: <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> On 19 Oct 2014, at 11:20, Herbert Valerio Riedel wrote: > -- This module deliberately declares orphan instances: > {-# OPTIONS_GHC -fno-warn-orphans #-} > > -- | Optional instance of 'Text.Show.Show' for functions: > -- > -- > instance Show (a -> b) where > -- > showsPrec _ _ = showString \"\\" > -- > ----------------------------------------------------------------------------- > Should this module be > deprecated, removed, alternatively, should the `Show` instance be made a > non-orphan (e.g. by importing it by the `Prelude` module), or shall this > curiousity be just left untouched in `base` in its current form? Under no circumstances should this instance ever be visible from the Prelude. It was deliberately made an orphan because the instance is non-conformant to the intended semantics of the Show class. Having a default instance of Show for functions would be a disaster, by causing static type error messages that indicate an arity problem, to become erratic runtime behaviours instead (without even throwing an exception). Nevertheless, it was found many years ago that lots of people defined this instance as a convenience, or a debugging aid. And once it accidentally gets into two different released libraries, the orphans conflict, and the libraries become unusable together. This is why a single "standard" orphan was thought preferable to multiple conflicting orphans. In summary, if you want this instance, you should know that it is problematic, and that you need to import it explicitly. Regards, Malcolm From lemming at henning-thielemann.de Sun Oct 19 14:02:23 2014 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Sun, 19 Oct 2014 16:02:23 +0200 (CEST) Subject: Future of "Text.Show.Functions" module In-Reply-To: <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> References: <87zjcs7448.fsf@gnu.org> <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> Message-ID: On Sun, 19 Oct 2014, Malcolm Wallace wrote: > Nevertheless, it was found many years ago that lots of people defined > this instance as a convenience, or a debugging aid. If its only purpose is debugging, how about moving it under the Debug directory in the module hierarchy? From allbery.b at gmail.com Sun Oct 19 14:36:35 2014 From: allbery.b at gmail.com (Brandon Allbery) Date: Sun, 19 Oct 2014 10:36:35 -0400 Subject: [core libraries] Future of "Text.Show.Functions" module In-Reply-To: References: <87zjcs7448.fsf@gnu.org> Message-ID: On Sun, Oct 19, 2014 at 8:59 AM, Michael Snoyman wrote: > I think this really brings up the question of what `Show` should be used > for. If the goal is to be simple serialization with `Read` as the > inverse[1], then this is clearly a nonsense instance and shouldn't be > included. I think I've said before that it would be nice if we had a specific class for debugging displays, given that Read/Show are generally oriented toward serialization. Sadly, this would end up requiring a lot of repetition, since you couldn't sanely fall back on a default Show instance to get a notional Gist (or whatever) instance. -- 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 greg at gregweber.info Sun Oct 19 16:17:25 2014 From: greg at gregweber.info (Greg Weber) Date: Sun, 19 Oct 2014 09:17:25 -0700 Subject: FilePath modification proposal In-Reply-To: <5443B450.2030408@ibotty.net> References: <5443B450.2030408@ibotty.net> Message-ID: I personally think that checking in any non-platform dependent file is usually a best practice. Not requiring the generator to be run when initially checking out the code might seem unsafe, but seeing the generated code in the diff communicates that you properly ran the generator on your local system (not just the first time checking out, but every time). On Sun, Oct 19, 2014 at 5:53 AM, Tobias Florek wrote: > hi, > > have no vote in the committee, but re > > > * Change 1: Add -<.> as an alias for replaceExtension with the same > >> precedence as <.> >> > > i am very much in favor. i have (locally) defined that or a similar alias > a few times already. > > > the other changes are imo your choice alone, as you are the (only?) person > maintaining it. (i prefer not checking in auto-generated files, but... > whatever.) > > thank you, neill, for maintaining filepath, > tobias florek > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Sun Oct 19 19:00:23 2014 From: michael at snoyman.com (Michael Snoyman) Date: Sun, 19 Oct 2014 22:00:23 +0300 Subject: Future of "Text.Show.Functions" module In-Reply-To: <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> References: <87zjcs7448.fsf@gnu.org> <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> Message-ID: On Sun, Oct 19, 2014 at 4:55 PM, Malcolm Wallace wrote: > > On 19 Oct 2014, at 11:20, Herbert Valerio Riedel wrote: > > > -- This module deliberately declares orphan instances: > > {-# OPTIONS_GHC -fno-warn-orphans #-} > > > > -- | Optional instance of 'Text.Show.Show' for functions: > > -- > > -- > instance Show (a -> b) where > > -- > showsPrec _ _ = showString \"\\" > > -- > > > ----------------------------------------------------------------------------- > > Should this module be > > deprecated, removed, alternatively, should the `Show` instance be made a > > non-orphan (e.g. by importing it by the `Prelude` module), or shall this > > curiousity be just left untouched in `base` in its current form? > > > Under no circumstances should this instance ever be visible from the > Prelude. > > It was deliberately made an orphan because the instance is non-conformant > to the intended semantics of the Show class. Having a default instance of > Show for functions would be a disaster, by causing static type error > messages that indicate an arity problem, to become erratic runtime > behaviours instead (without even throwing an exception). > > While I'm sensitive to this position (thus my very reluctant +0.5 on merging into Prelude), I don't see the "disaster" you're referring to. The only case I can picture where this might happen is when you have a value that you are *only* ever displaying, not using in any other way. But won't it become painfully obvious very quickly that you messed up? Can you describe concretely a scenario where the presence of this instance in Prelude would cause a disaster? And if the instance is really as bad as that, I think having it in base at all is a mistake. All it takes it one library upstream from you to import that module, and you've been infected. Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From allbery.b at gmail.com Sun Oct 19 19:03:11 2014 From: allbery.b at gmail.com (Brandon Allbery) Date: Sun, 19 Oct 2014 15:03:11 -0400 Subject: Future of "Text.Show.Functions" module In-Reply-To: References: <87zjcs7448.fsf@gnu.org> <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> Message-ID: On Sun, Oct 19, 2014 at 3:00 PM, Michael Snoyman wrote: > And if the instance is really as bad as that, I think having it in base at > all is a mistake. All it takes it one library upstream from you to import > that module, and you've been infected. It's useful in ghci. Which suggests a possible solution: perhaps things like this that are mostly useful from ghci should go into a GHC.Interactive hierarchy. -- 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 michael at snoyman.com Sun Oct 19 19:07:44 2014 From: michael at snoyman.com (Michael Snoyman) Date: Sun, 19 Oct 2014 22:07:44 +0300 Subject: [core libraries] Re: Future of "Text.Show.Functions" module In-Reply-To: References: <87zjcs7448.fsf@gnu.org> <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> Message-ID: On Sun, Oct 19, 2014 at 10:03 PM, Brandon Allbery wrote: > On Sun, Oct 19, 2014 at 3:00 PM, Michael Snoyman > wrote: > >> And if the instance is really as bad as that, I think having it in base >> at all is a mistake. All it takes it one library upstream from you to >> import that module, and you've been infected. > > > It's useful in ghci. > > Which suggests a possible solution: perhaps things like this that are > mostly useful from ghci should go into a GHC.Interactive hierarchy. > > > Based on this thread, I thought it was specifically in GHCi when it was *not* considered helpful. Without the instance: Prelude> print concat :2:1: No instance for (Show ([[a0]] -> [a0])) arising from a use of ?print? In the expression: print concat In an equation for ?it?: it = print concat at least tells me what I'm looking at, whereas: Prelude> import Text.Show.Functions Prelude Text.Show.Functions> print concat gives no important info. However, if this is all for GHCi's sake, isn't it really a moot point: Prelude Text.Show.Functions> :t concat concat :: [[a]] -> [a] I'd consider this instance useful for the case of: data Foo = Foo { foo1 :: Int, foo2 :: Double, foo3 :: Char -> Bool } deriving Show Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sun Oct 19 21:24:25 2014 From: ekmett at gmail.com (Edward Kmett) Date: Sun, 19 Oct 2014 17:24:25 -0400 Subject: Future of "Text.Show.Functions" module In-Reply-To: <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> References: <87zjcs7448.fsf@gnu.org> <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> Message-ID: <9E5FAD75-9164-4C83-8E6D-87F4A79082AF@gmail.com> Malcolm's reasoning matches mine perfectly here. The instance should not be standard. It should never go into Prelude. It standardizes on one of many viable choices. However, it is one of those things that folks, rightly or wrongly, define fairly often and removing it would increase conflicts among orphans doing the same thing. I'd strongly advocate holding your nose and leaving it there. Sent from my iPhone > On Oct 19, 2014, at 9:55 AM, Malcolm Wallace wrote: > > >> On 19 Oct 2014, at 11:20, Herbert Valerio Riedel wrote: >> >> -- This module deliberately declares orphan instances: >> {-# OPTIONS_GHC -fno-warn-orphans #-} >> >> -- | Optional instance of 'Text.Show.Show' for functions: >> -- >> -- > instance Show (a -> b) where >> -- > showsPrec _ _ = showString \"\\" >> -- >> ----------------------------------------------------------------------------- >> Should this module be >> deprecated, removed, alternatively, should the `Show` instance be made a >> non-orphan (e.g. by importing it by the `Prelude` module), or shall this >> curiousity be just left untouched in `base` in its current form? > > > Under no circumstances should this instance ever be visible from the Prelude. > > It was deliberately made an orphan because the instance is non-conformant to the intended semantics of the Show class. Having a default instance of Show for functions would be a disaster, by causing static type error messages that indicate an arity problem, to become erratic runtime behaviours instead (without even throwing an exception). > > Nevertheless, it was found many years ago that lots of people defined this instance as a convenience, or a debugging aid. And once it accidentally gets into two different released libraries, the orphans conflict, and the libraries become unusable together. This is why a single "standard" orphan was thought preferable to multiple conflicting orphans. > > In summary, if you want this instance, you should know that it is problematic, and that you need to import it explicitly. > > Regards, > Malcolm > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries From roma at ro-che.info Sun Oct 19 21:25:17 2014 From: roma at ro-che.info (Roman Cheplyaka) Date: Mon, 20 Oct 2014 00:25:17 +0300 Subject: Future of "Text.Show.Functions" module In-Reply-To: References: <87zjcs7448.fsf@gnu.org> <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> Message-ID: <54442C3D.60202@ro-che.info> On 19/10/14 22:00, Michael Snoyman wrote: > On Sun, Oct 19, 2014 at 4:55 PM, Malcolm Wallace > wrote: > >> >> On 19 Oct 2014, at 11:20, Herbert Valerio Riedel wrote: >> >>> -- This module deliberately declares orphan instances: >>> {-# OPTIONS_GHC -fno-warn-orphans #-} >>> >>> -- | Optional instance of 'Text.Show.Show' for functions: >>> -- >>> -- > instance Show (a -> b) where >>> -- > showsPrec _ _ = showString \"\\" >>> -- >>> >> ----------------------------------------------------------------------------- >>> Should this module be >>> deprecated, removed, alternatively, should the `Show` instance be made a >>> non-orphan (e.g. by importing it by the `Prelude` module), or shall this >>> curiousity be just left untouched in `base` in its current form? >> >> >> Under no circumstances should this instance ever be visible from the >> Prelude. >> >> It was deliberately made an orphan because the instance is non-conformant >> to the intended semantics of the Show class. Having a default instance of >> Show for functions would be a disaster, by causing static type error >> messages that indicate an arity problem, to become erratic runtime >> behaviours instead (without even throwing an exception). >> >> > While I'm sensitive to this position (thus my very reluctant +0.5 on > merging into Prelude), I don't see the "disaster" you're referring to. The > only case I can picture where this might happen is when you have a value > that you are *only* ever displaying, not using in any other way. But won't > it become painfully obvious very quickly that you messed up? A simple example would be using show to produce debug output like this: debug $ show $ f x1 x2 ... where you missed some of the arguments for f. For the record, I agree with Malcolm's reasoning and would like the instance to be left as it is now. Roman From hvr at gnu.org Mon Oct 20 08:57:24 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Mon, 20 Oct 2014 10:57:24 +0200 Subject: Future of "Text.Show.Functions" module In-Reply-To: <9E5FAD75-9164-4C83-8E6D-87F4A79082AF@gmail.com> (Edward Kmett's message of "Sun, 19 Oct 2014 17:24:25 -0400") References: <87zjcs7448.fsf@gnu.org> <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> <9E5FAD75-9164-4C83-8E6D-87F4A79082AF@gmail.com> Message-ID: <87mw8razkb.fsf@gnu.org> On 2014-10-19 at 23:24:25 +0200, Edward Kmett wrote: > Malcolm's reasoning matches mine perfectly here. > > The instance should not be standard. > > It should never go into Prelude. > > It standardizes on one of many viable choices. > > However, it is one of those things that folks, rightly or wrongly, > define fairly often and removing it would increase conflicts among > orphans doing the same thing. > > I'd strongly advocate holding your nose and leaving it there. Fair enough. But what about adding a WARNING pragma such as (modulo wording): module Text.Show.Functions {-# WARNING "Here Be Dragons, RTFM!" -# } where and adding a bit more documentation pointing out the dos and donts of using that module (like explaining it is not be advisable import that module in a public library package to be placed on Hackage due to the global namespace issue of such instances) Cheers, hvr From hvr at gnu.org Mon Oct 20 13:26:09 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Mon, 20 Oct 2014 15:26:09 +0200 Subject: FilePath modification proposal In-Reply-To: (Neil Mitchell's message of "Sun, 19 Oct 2014 13:35:02 +0100") References: Message-ID: <87iojec1ou.fsf@gnu.org> On 2014-10-19 at 14:35:02 +0200, Neil Mitchell wrote: [...] > * Change 3: Check in the generated test code Can't something in the style of https://hackage.haskell.org/package/doctest be used to avoid having to run a generator manually? Btw, Haddock has even markup support for QC properties via "prop>"-prefixed code-blocks. Cheers, hvr From ndmitchell at gmail.com Mon Oct 20 14:22:43 2014 From: ndmitchell at gmail.com (Neil Mitchell) Date: Mon, 20 Oct 2014 15:22:43 +0100 Subject: FilePath modification proposal In-Reply-To: <87iojec1ou.fsf@gnu.org> References: <87iojec1ou.fsf@gnu.org> Message-ID: > Can't something in the style of > > https://hackage.haskell.org/package/doctest > > be used to avoid having to run a generator manually? It would, but then instead of generating a file (pretty easy), I have to go through the GHC API (a lot more fiddly). Alternatively, I could just have the tester spit out a temporary .hs file and run over it in one go - which works, but means all the nice Cabal stuff for dependencies of the test suite get a bit lost and I have to assume a "good" GHC on the $PATH. Both avoid checking in generated code, but end up a bit more complex in other respects. > Btw, Haddock has even markup support for QC properties via > "prop>"-prefixed code-blocks. Yes, but here I want slightly lighter weight properties (I infer what is a variable and what isn't), and also multi-module properties (most properties are tested against both .Windows and .Posix paths). I almost always find I can get slightly cleaner tests by writing a generator myself, and that the effort writing the generator is minimal and reducing the difficulty of writing tests makes me write more of them. Thanks, Neil From ekmett at gmail.com Mon Oct 20 14:41:05 2014 From: ekmett at gmail.com (Edward Kmett) Date: Mon, 20 Oct 2014 10:41:05 -0400 Subject: Future of "Text.Show.Functions" module In-Reply-To: <87mw8razkb.fsf@gnu.org> References: <87zjcs7448.fsf@gnu.org> <02032B20-BB64-4535-8466-9A24E7B20CA9@me.com> <9E5FAD75-9164-4C83-8E6D-87F4A79082AF@gmail.com> <87mw8razkb.fsf@gnu.org> Message-ID: I'd have no objection to a well-worded warning. On Mon, Oct 20, 2014 at 4:57 AM, Herbert Valerio Riedel wrote: > On 2014-10-19 at 23:24:25 +0200, Edward Kmett wrote: > > Malcolm's reasoning matches mine perfectly here. > > > > The instance should not be standard. > > > > It should never go into Prelude. > > > > It standardizes on one of many viable choices. > > > > However, it is one of those things that folks, rightly or wrongly, > > define fairly often and removing it would increase conflicts among > > orphans doing the same thing. > > > > I'd strongly advocate holding your nose and leaving it there. > > Fair enough. But what about adding a WARNING pragma such as > (modulo wording): > > > module Text.Show.Functions {-# WARNING "Here Be Dragons, RTFM!" -# } > where > > > and adding a bit more documentation pointing out the dos and donts of > using that module (like explaining it is not be advisable import that > module in a public library package to be placed on Hackage due to the > global namespace issue of such instances) > > Cheers, > hvr > -------------- next part -------------- An HTML attachment was scrubbed... URL: From andreas.abel at ifi.lmu.de Mon Oct 20 21:00:07 2014 From: andreas.abel at ifi.lmu.de (Andreas Abel) Date: Tue, 21 Oct 2014 00:00:07 +0300 Subject: [core libraries] Future of "Text.Show.Functions" module In-Reply-To: References: <87zjcs7448.fsf@gnu.org> Message-ID: <544577D7.3060304@ifi.lmu.de> Strongly +1 for Show printing valid Haskell. I'd implement showing for functions as data Function = Function instance Show (a -> b) where show f = "Function" (I would not assume Haskellers expect a Show-ed function to be Read-able.) For simple user-friendly display we should add a class to Text.PrettyPrint class Pretty a where pretty :: a -> Doc pretty = text . prettyShow prettyShow :: a -> String prettyShow = render . pretty This class should become standard for implementing simple pretty printing (instead of the abuse of Show). Cheers, Andreas On 19.10.2014 17:36, Brandon Allbery wrote: > On Sun, Oct 19, 2014 at 8:59 AM, Michael Snoyman > wrote: > > I think this really brings up the question of what `Show` should be > used for. If the goal is to be simple serialization with `Read` as > the inverse[1], then this is clearly a nonsense instance and > shouldn't be included. > > > I think I've said before that it would be nice if we had a specific > class for debugging displays, given that Read/Show are generally > oriented toward serialization. Sadly, this would end up requiring a lot > of repetition, since you couldn't sanely fall back on a default Show > instance to get a notional Gist (or whatever) instance. -- 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 ekmett at gmail.com Wed Oct 22 17:30:47 2014 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 22 Oct 2014 13:30:47 -0400 Subject: Proposal: Let OpenGL depend on the StateVar package Message-ID: We're currently actively working on writing better SDL 2 bindings in sdl2. For various reasons, it can't depend on the OpenGL package directly, but it needs a state variable construction. Sadly, not every platform with SDL 2 has OpenGL -- thanks Microsoft. We'd like to depend on the StateVar package, but then we'll get two versions of the notion of a StateVar that conflict. By *far* the cleanest option for us moving forward would be if OpenGL switched to using the externalStateVar package that you also maintain, then we could incur a dependency on that. I realize that when this was last proposed there was some pushback from the Haskell Platform, but otherwise what we're going to start seeing is a profusion of almost-compatible APIs, which is the very thing that the Haskell Platform is meant to prevent. This would necessitate adding StateVar to the Haskell Platform, as OpenGL is in the Haskell Platform. The package is maintained by the same maintainer as the current OpenGL package. Discussion Period: 2 weeks -Edward Kmett -------------- next part -------------- An HTML attachment was scrubbed... URL: From alpmestan at gmail.com Wed Oct 22 17:40:55 2014 From: alpmestan at gmail.com (Alp Mestanogullari) Date: Wed, 22 Oct 2014 19:40:55 +0200 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: +1, both packages need it and should really just be using the same implementation. Otherwise we'll just end up with conflicts when using sdl2 *and* OpenGL or we'll be juggling between two statevars implementations imported qualified that really are the same thing. On Wed, Oct 22, 2014 at 7:30 PM, Edward Kmett wrote: > We're currently actively working on writing better SDL 2 bindings in sdl2. > > For various reasons, it can't depend on the OpenGL package directly, but > it needs a state variable construction. > > Sadly, not every platform with SDL 2 has OpenGL -- thanks Microsoft. > > We'd like to depend on the StateVar package, but then we'll get two > versions of the notion of a StateVar that conflict. > > By *far* the cleanest option for us moving forward would be if OpenGL switched > to using the externalStateVar package that you also maintain, then we > could incur a dependency on that. > > I realize that when this was last proposed there was some pushback from > the Haskell Platform, but otherwise what we're going to start seeing is a > profusion of almost-compatible APIs, which is the very thing that the > Haskell Platform is meant to prevent. > > > This would necessitate adding StateVar to the Haskell Platform, as OpenGL > is in the Haskell Platform. > > > The package is maintained by the same maintainer as the current OpenGL > package. > > > Discussion Period: 2 weeks > > > -Edward Kmett > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -- Alp Mestanogullari -------------- next part -------------- An HTML attachment was scrubbed... URL: From dons00 at gmail.com Wed Oct 22 17:44:07 2014 From: dons00 at gmail.com (Don Stewart) Date: Wed, 22 Oct 2014 18:44:07 +0100 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: Previous problems with StateVar apply - name likely to mislead users into using something they shouldn't. If it was named OpenGL-utils no one would mind... On Wednesday, 22 October 2014, Edward Kmett wrote: > We're currently actively working on writing better SDL 2 bindings in sdl2. > > For various reasons, it can't depend on the OpenGL package directly, but > it needs a state variable construction. > > Sadly, not every platform with SDL 2 has OpenGL -- thanks Microsoft. > > We'd like to depend on the StateVar package, but then we'll get two > versions of the notion of a StateVar that conflict. > > By *far* the cleanest option for us moving forward would be if OpenGL switched > to using the externalStateVar package that you also maintain, then we > could incur a dependency on that. > > I realize that when this was last proposed there was some pushback from > the Haskell Platform, but otherwise what we're going to start seeing is a > profusion of almost-compatible APIs, which is the very thing that the > Haskell Platform is meant to prevent. > > > This would necessitate adding StateVar to the Haskell Platform, as OpenGL > is in the Haskell Platform. > > > The package is maintained by the same maintainer as the current OpenGL > package. > > > Discussion Period: 2 weeks > > > -Edward Kmett > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Wed Oct 22 18:23:40 2014 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 22 Oct 2014 14:23:40 -0400 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: I have no particular objection to renaming the package -- though it isn't my library. We probably would not want to rename the actual types inside the package though. (Moving them to a namespace that is less front-and-center, probably shouldn't be a pain point though). If we bikeshed this to death the proposal may get rejected by the maintainers as too big of an API change. Having the existing module just re-export something supplied by an external package is a small change. OpenGL has a very large user base. But that said, it isn't actually anything about OpenGL, so much as how to manipulate a piece of IO-based state that is gettable/settable in an external API. I'm working with a bunch of ugly imperative libraries these days where I have such concerns, OpenEXR, SDL, etc. all expose similar imperative getter/setter APIs -- none of which have anything in particular to do with OpenGL, so the name OpenGL-utils is pretty bad, since it'd be for stuff you can use when you don't or can't depend on OpenGL, that OpenGL just happens to want too. -Edward On Wed, Oct 22, 2014 at 1:44 PM, Don Stewart wrote: > Previous problems with StateVar apply - name likely to mislead users into > using something they shouldn't. > > If it was named OpenGL-utils no one would mind... > > > On Wednesday, 22 October 2014, Edward Kmett wrote: > >> We're currently actively working on writing better SDL 2 bindings in sdl2 >> . >> >> For various reasons, it can't depend on the OpenGL package directly, but >> it needs a state variable construction. >> >> Sadly, not every platform with SDL 2 has OpenGL -- thanks Microsoft. >> >> We'd like to depend on the StateVar package, but then we'll get two >> versions of the notion of a StateVar that conflict. >> >> By *far* the cleanest option for us moving forward would be if OpenGL switched >> to using the externalStateVar package that you also maintain, then we >> could incur a dependency on that. >> >> I realize that when this was last proposed there was some pushback from >> the Haskell Platform, but otherwise what we're going to start seeing is a >> profusion of almost-compatible APIs, which is the very thing that the >> Haskell Platform is meant to prevent. >> >> >> This would necessitate adding StateVar to the Haskell Platform, as OpenGL >> is in the Haskell Platform. >> >> >> The package is maintained by the same maintainer as the current OpenGL >> package. >> >> >> Discussion Period: 2 weeks >> >> >> -Edward Kmett >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ganesh at earth.li Wed Oct 22 19:13:38 2014 From: ganesh at earth.li (Ganesh Sittampalam) Date: Wed, 22 Oct 2014 20:13:38 +0100 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: References: Message-ID: <544801E2.2070301@earth.li> On 16/10/2014 18:14, David Feuer wrote: > These functions can be lifted pretty much straight out of Data.Sequence. > In particular, foldrWithIndex makes for a particularly nice expression > of a fusing findIndices function, as is present in Data.Sequence. Do these do anything better than just adding indicies first with the standard zip [0..] idiom? Cheers, Ganesh From david.feuer at gmail.com Wed Oct 22 19:19:09 2014 From: david.feuer at gmail.com (David Feuer) Date: Wed, 22 Oct 2014 15:19:09 -0400 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: <544801E2.2070301@earth.li> References: <544801E2.2070301@earth.li> Message-ID: Yes, they do. In particular, the zip can only fuse with one of the two lists so the Ints could be unboxed, or fusion optimizations could happen with the list folded over, but not both. The fold_WithIndex function can manage both at once. That said, I think there have been some pretty good arguments against adding these, or at least against adding them with these names. On Oct 22, 2014 3:13 PM, "Ganesh Sittampalam" wrote: > On 16/10/2014 18:14, David Feuer wrote: > >> These functions can be lifted pretty much straight out of Data.Sequence. >> In particular, foldrWithIndex makes for a particularly nice expression >> of a fusing findIndices function, as is present in Data.Sequence. >> > > Do these do anything better than just adding indicies first with the > standard zip [0..] idiom? > > Cheers, > > Ganesh > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ganesh at earth.li Wed Oct 22 20:40:26 2014 From: ganesh at earth.li (Ganesh Sittampalam) Date: Wed, 22 Oct 2014 21:40:26 +0100 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: References: <544801E2.2070301@earth.li> Message-ID: <5448163A.40202@earth.li> I see, thanks. Could this be done via a rewrite rule from that idiom to an internal implementation function instead? On 22/10/2014 20:19, David Feuer wrote: > Yes, they do. In particular, the zip can only fuse with one of the two > lists so the Ints could be unboxed, or fusion optimizations could happen > with the list folded over, but not both. The fold_WithIndex function can > manage both at once. That said, I think there have been some pretty good > arguments against adding these, or at least against adding them with > these names. > > On Oct 22, 2014 3:13 PM, "Ganesh Sittampalam" > wrote: > > On 16/10/2014 18:14, David Feuer wrote: > > These functions can be lifted pretty much straight out of > Data.Sequence. > In particular, foldrWithIndex makes for a particularly nice > expression > of a fusing findIndices function, as is present in Data.Sequence. > > > Do these do anything better than just adding indicies first with the > standard zip [0..] idiom? > > Cheers, > > Ganesh > > _________________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/__mailman/listinfo/libraries > > From ganesh at earth.li Wed Oct 22 20:46:47 2014 From: ganesh at earth.li (Ganesh Sittampalam) Date: Wed, 22 Oct 2014 21:46:47 +0100 Subject: [core libraries] Future of "Text.Show.Functions" module In-Reply-To: <544577D7.3060304@ifi.lmu.de> References: <87zjcs7448.fsf@gnu.org> <544577D7.3060304@ifi.lmu.de> Message-ID: <544817B7.6020504@earth.li> What's the benefit of this implementation of Show (a -> b)? Even if it causes the output to be parseable, it's unlikely to typecheck. On 20/10/2014 22:00, Andreas Abel wrote: > Strongly +1 for Show printing valid Haskell. > > I'd implement showing for functions as > > data Function = Function > > instance Show (a -> b) where > show f = "Function" > > (I would not assume Haskellers expect a Show-ed function to be Read-able.) > > For simple user-friendly display we should add a class to Text.PrettyPrint > > class Pretty a where > pretty :: a -> Doc > pretty = text . prettyShow > > prettyShow :: a -> String > prettyShow = render . pretty > > This class should become standard for implementing simple pretty > printing (instead of the abuse of Show). > > Cheers, > Andreas > > > On 19.10.2014 17:36, Brandon Allbery wrote: >> On Sun, Oct 19, 2014 at 8:59 AM, Michael Snoyman > > wrote: >> >> I think this really brings up the question of what `Show` should be >> used for. If the goal is to be simple serialization with `Read` as >> the inverse[1], then this is clearly a nonsense instance and >> shouldn't be included. >> >> >> I think I've said before that it would be nice if we had a specific >> class for debugging displays, given that Read/Show are generally >> oriented toward serialization. Sadly, this would end up requiring a lot >> of repetition, since you couldn't sanely fall back on a default Show >> instance to get a notional Gist (or whatever) instance. > > > From ollie at ocharles.org.uk Wed Oct 22 22:01:32 2014 From: ollie at ocharles.org.uk (Oliver Charles) Date: Wed, 22 Oct 2014 23:01:32 +0100 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: I'm not up to date on why this didn't happen last time, but I can appreciate it being an unnecessary change. However, now the change seems to be more substantiated. Firstly, as others have expressed - this is a common pattern in C libraries where mutation through IO is really the only way to go. A single name to encapsulate both sides of the equation is pretty nice here - it drastically reduces the API size which leads to libraries that (I believe) are easier to learn. This usage is particularly telling though, because this an abstraction that's likely to be used by both of these libraries in the majority of projects. While it's true you don't have to use SDL with OpenGL, my hunch is that the majority will. If we can't get this stuff factored out to a common library then: * SDL needs to explicitly use get/set everywhere * SDL copies Data.StateVar and uses it locally. Now all the names have to be imported qualified, and things got a ton harder * SDL has its own Data.StateVar with different names. Now we've put burden on the user to juggle between various names, and introduced even more operators (many already believe Haskell has too many - I'd rather not add *more*!) None of these are compelling options, and it'll be a real shame if OpenGL dominates this design pattern - essentially ruling out its usage in the game development/graphics programming community. +1, if that's wasn't obvious ;) - ocharles -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Wed Oct 22 22:13:09 2014 From: david.feuer at gmail.com (David Feuer) Date: Wed, 22 Oct 2014 18:13:09 -0400 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: <5448163A.40202@earth.li> References: <544801E2.2070301@earth.li> <5448163A.40202@earth.li> Message-ID: I think the answer is almost certainly no. The zipWith will turn into a foldr2, and there's no vaguely sure way of snatching that before it fuses with a build form and is lost forever. You'd end up with some very complicated rules that only did something useful when the phase of the moon was right. I'm pretty sure it's not worth trying. On Oct 22, 2014 4:40 PM, "Ganesh Sittampalam" wrote: > I see, thanks. Could this be done via a rewrite rule from that idiom to > an internal implementation function instead? > > On 22/10/2014 20:19, David Feuer wrote: > > Yes, they do. In particular, the zip can only fuse with one of the two > > lists so the Ints could be unboxed, or fusion optimizations could happen > > with the list folded over, but not both. The fold_WithIndex function can > > manage both at once. That said, I think there have been some pretty good > > arguments against adding these, or at least against adding them with > > these names. > > > > On Oct 22, 2014 3:13 PM, "Ganesh Sittampalam" > > wrote: > > > > On 16/10/2014 18:14, David Feuer wrote: > > > > These functions can be lifted pretty much straight out of > > Data.Sequence. > > In particular, foldrWithIndex makes for a particularly nice > > expression > > of a fusing findIndices function, as is present in Data.Sequence. > > > > > > Do these do anything better than just adding indicies first with the > > standard zip [0..] idiom? > > > > Cheers, > > > > Ganesh > > > > _________________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://www.haskell.org/__mailman/listinfo/libraries > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rwbarton at gmail.com Wed Oct 22 22:15:10 2014 From: rwbarton at gmail.com (Reid Barton) Date: Wed, 22 Oct 2014 18:15:10 -0400 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: As a point in the package name bike-shedding space, how about "foreign-state"? Seems suitably descriptive yet general, while also dissuading casual use with the scary word "foreign". Regards, Reid Barton On Wed, Oct 22, 2014 at 2:23 PM, Edward Kmett wrote: > I have no particular objection to renaming the package -- though it isn't > my library. > > We probably would not want to rename the actual types inside the package > though. (Moving them to a namespace that is less front-and-center, probably > shouldn't be a pain point though). If we bikeshed this to death the > proposal may get rejected by the maintainers as too big of an API change. > Having the existing module just re-export something supplied by an external > package is a small change. > > OpenGL has a very large user base. > > But that said, it isn't actually anything about OpenGL, so much as how to > manipulate a piece of IO-based state that is gettable/settable in an > external API. I'm working with a bunch of ugly imperative libraries these > days where I have such concerns, OpenEXR, SDL, etc. all expose similar > imperative getter/setter APIs -- none of which have anything in particular > to do with OpenGL, so the name OpenGL-utils is pretty bad, since it'd be > for stuff you can use when you don't or can't depend on OpenGL, that OpenGL > just happens to want too. > > -Edward > > On Wed, Oct 22, 2014 at 1:44 PM, Don Stewart wrote: > >> Previous problems with StateVar apply - name likely to mislead users >> into using something they shouldn't. >> >> If it was named OpenGL-utils no one would mind... >> >> >> On Wednesday, 22 October 2014, Edward Kmett wrote: >> >>> We're currently actively working on writing better SDL 2 bindings in >>> sdl2. >>> >>> For various reasons, it can't depend on the OpenGL package directly, >>> but it needs a state variable construction. >>> >>> Sadly, not every platform with SDL 2 has OpenGL -- thanks Microsoft. >>> >>> We'd like to depend on the StateVar package, but then we'll get two >>> versions of the notion of a StateVar that conflict. >>> >>> By *far* the cleanest option for us moving forward would be if OpenGL switched >>> to using the externalStateVar package that you also maintain, then we >>> could incur a dependency on that. >>> >>> I realize that when this was last proposed there was some pushback from >>> the Haskell Platform, but otherwise what we're going to start seeing is a >>> profusion of almost-compatible APIs, which is the very thing that the >>> Haskell Platform is meant to prevent. >>> >>> >>> This would necessitate adding StateVar to the Haskell Platform, as >>> OpenGL is in the Haskell Platform. >>> >>> >>> The package is maintained by the same maintainer as the current OpenGL >>> package. >>> >>> >>> Discussion Period: 2 weeks >>> >>> >>> -Edward Kmett >>> >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Wed Oct 22 22:35:49 2014 From: david.feuer at gmail.com (David Feuer) Date: Wed, 22 Oct 2014 18:35:49 -0400 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: I am -1 on the name foreign-state, because there's absolutely nothing even remotely foreign about anything in that package. On Wed, Oct 22, 2014 at 6:15 PM, Reid Barton wrote: > As a point in the package name bike-shedding space, how about > "foreign-state"? Seems suitably descriptive yet general, while also > dissuading casual use with the scary word "foreign". > > Regards, > Reid Barton > > > On Wed, Oct 22, 2014 at 2:23 PM, Edward Kmett wrote: > >> I have no particular objection to renaming the package -- though it isn't >> my library. >> >> We probably would not want to rename the actual types inside the package >> though. (Moving them to a namespace that is less front-and-center, probably >> shouldn't be a pain point though). If we bikeshed this to death the >> proposal may get rejected by the maintainers as too big of an API change. >> Having the existing module just re-export something supplied by an external >> package is a small change. >> >> OpenGL has a very large user base. >> >> But that said, it isn't actually anything about OpenGL, so much as how to >> manipulate a piece of IO-based state that is gettable/settable in an >> external API. I'm working with a bunch of ugly imperative libraries these >> days where I have such concerns, OpenEXR, SDL, etc. all expose similar >> imperative getter/setter APIs -- none of which have anything in particular >> to do with OpenGL, so the name OpenGL-utils is pretty bad, since it'd be >> for stuff you can use when you don't or can't depend on OpenGL, that OpenGL >> just happens to want too. >> >> -Edward >> >> On Wed, Oct 22, 2014 at 1:44 PM, Don Stewart wrote: >> >>> Previous problems with StateVar apply - name likely to mislead users >>> into using something they shouldn't. >>> >>> If it was named OpenGL-utils no one would mind... >>> >>> >>> On Wednesday, 22 October 2014, Edward Kmett wrote: >>> >>>> We're currently actively working on writing better SDL 2 bindings in >>>> sdl2. >>>> >>>> For various reasons, it can't depend on the OpenGL package directly, >>>> but it needs a state variable construction. >>>> >>>> Sadly, not every platform with SDL 2 has OpenGL -- thanks Microsoft. >>>> >>>> We'd like to depend on the StateVar package, but then we'll get two >>>> versions of the notion of a StateVar that conflict. >>>> >>>> By *far* the cleanest option for us moving forward would be if OpenGL switched >>>> to using the externalStateVar package that you also maintain, then we >>>> could incur a dependency on that. >>>> >>>> I realize that when this was last proposed there was some pushback from >>>> the Haskell Platform, but otherwise what we're going to start seeing is a >>>> profusion of almost-compatible APIs, which is the very thing that the >>>> Haskell Platform is meant to prevent. >>>> >>>> >>>> This would necessitate adding StateVar to the Haskell Platform, as >>>> OpenGL is in the Haskell Platform. >>>> >>>> >>>> The package is maintained by the same maintainer as the current OpenGL >>>> package. >>>> >>>> >>>> Discussion Period: 2 weeks >>>> >>>> >>>> -Edward Kmett >>>> >>> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Thu Oct 23 00:00:24 2014 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 22 Oct 2014 20:00:24 -0400 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: imperative-state then? On Wed, Oct 22, 2014 at 6:15 PM, Reid Barton wrote: > As a point in the package name bike-shedding space, how about > "foreign-state"? Seems suitably descriptive yet general, while also > dissuading casual use with the scary word "foreign". > > Regards, > Reid Barton > > > On Wed, Oct 22, 2014 at 2:23 PM, Edward Kmett wrote: > >> I have no particular objection to renaming the package -- though it isn't >> my library. >> >> We probably would not want to rename the actual types inside the package >> though. (Moving them to a namespace that is less front-and-center, probably >> shouldn't be a pain point though). If we bikeshed this to death the >> proposal may get rejected by the maintainers as too big of an API change. >> Having the existing module just re-export something supplied by an external >> package is a small change. >> >> OpenGL has a very large user base. >> >> But that said, it isn't actually anything about OpenGL, so much as how to >> manipulate a piece of IO-based state that is gettable/settable in an >> external API. I'm working with a bunch of ugly imperative libraries these >> days where I have such concerns, OpenEXR, SDL, etc. all expose similar >> imperative getter/setter APIs -- none of which have anything in particular >> to do with OpenGL, so the name OpenGL-utils is pretty bad, since it'd be >> for stuff you can use when you don't or can't depend on OpenGL, that OpenGL >> just happens to want too. >> >> -Edward >> >> On Wed, Oct 22, 2014 at 1:44 PM, Don Stewart wrote: >> >>> Previous problems with StateVar apply - name likely to mislead users >>> into using something they shouldn't. >>> >>> If it was named OpenGL-utils no one would mind... >>> >>> >>> On Wednesday, 22 October 2014, Edward Kmett wrote: >>> >>>> We're currently actively working on writing better SDL 2 bindings in >>>> sdl2. >>>> >>>> For various reasons, it can't depend on the OpenGL package directly, >>>> but it needs a state variable construction. >>>> >>>> Sadly, not every platform with SDL 2 has OpenGL -- thanks Microsoft. >>>> >>>> We'd like to depend on the StateVar package, but then we'll get two >>>> versions of the notion of a StateVar that conflict. >>>> >>>> By *far* the cleanest option for us moving forward would be if OpenGL switched >>>> to using the externalStateVar package that you also maintain, then we >>>> could incur a dependency on that. >>>> >>>> I realize that when this was last proposed there was some pushback from >>>> the Haskell Platform, but otherwise what we're going to start seeing is a >>>> profusion of almost-compatible APIs, which is the very thing that the >>>> Haskell Platform is meant to prevent. >>>> >>>> >>>> This would necessitate adding StateVar to the Haskell Platform, as >>>> OpenGL is in the Haskell Platform. >>>> >>>> >>>> The package is maintained by the same maintainer as the current OpenGL >>>> package. >>>> >>>> >>>> Discussion Period: 2 weeks >>>> >>>> >>>> -Edward Kmett >>>> >>> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Thu Oct 23 05:32:13 2014 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Thu, 23 Oct 2014 01:32:13 -0400 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: References: <544801E2.2070301@earth.li> <5448163A.40202@earth.li> Message-ID: i hate always asking this question: but do we have an example benchmark illustrating there being a substantial difference in peformance if fold(l/r)withIndex is defined directly rather than via the more "naive" composition? On Wed, Oct 22, 2014 at 6:13 PM, David Feuer wrote: > I think the answer is almost certainly no. The zipWith will turn into a > foldr2, and there's no vaguely sure way of snatching that before it fuses > with a build form and is lost forever. You'd end up with some very > complicated rules that only did something useful when the phase of the moon > was right. I'm pretty sure it's not worth trying. > On Oct 22, 2014 4:40 PM, "Ganesh Sittampalam" wrote: > >> I see, thanks. Could this be done via a rewrite rule from that idiom to >> an internal implementation function instead? >> >> On 22/10/2014 20:19, David Feuer wrote: >> > Yes, they do. In particular, the zip can only fuse with one of the two >> > lists so the Ints could be unboxed, or fusion optimizations could happen >> > with the list folded over, but not both. The fold_WithIndex function can >> > manage both at once. That said, I think there have been some pretty good >> > arguments against adding these, or at least against adding them with >> > these names. >> > >> > On Oct 22, 2014 3:13 PM, "Ganesh Sittampalam" > > > wrote: >> > >> > On 16/10/2014 18:14, David Feuer wrote: >> > >> > These functions can be lifted pretty much straight out of >> > Data.Sequence. >> > In particular, foldrWithIndex makes for a particularly nice >> > expression >> > of a fusing findIndices function, as is present in >> Data.Sequence. >> > >> > >> > Do these do anything better than just adding indicies first with the >> > standard zip [0..] idiom? >> > >> > Cheers, >> > >> > Ganesh >> > >> > _________________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://www.haskell.org/__mailman/listinfo/libraries >> > >> > >> >> > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Thu Oct 23 05:46:25 2014 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Thu, 23 Oct 2014 01:46:25 -0400 Subject: [core libraries] Future of "Text.Show.Functions" module In-Reply-To: <544817B7.6020504@earth.li> References: <87zjcs7448.fsf@gnu.org> <544577D7.3060304@ifi.lmu.de> <544817B7.6020504@earth.li> Message-ID: agreed, i'm strongly -1 on forcing a generic catchall a->b instance, especially since things like Show a => Show (Bool -> a) , are pretty useful! On Wed, Oct 22, 2014 at 4:46 PM, Ganesh Sittampalam wrote: > What's the benefit of this implementation of Show (a -> b)? Even if it > causes the output to be parseable, it's unlikely to typecheck. > > On 20/10/2014 22:00, Andreas Abel wrote: > > Strongly +1 for Show printing valid Haskell. > > > > I'd implement showing for functions as > > > > data Function = Function > > > > instance Show (a -> b) where > > show f = "Function" > > > > (I would not assume Haskellers expect a Show-ed function to be > Read-able.) > > > > For simple user-friendly display we should add a class to > Text.PrettyPrint > > > > class Pretty a where > > pretty :: a -> Doc > > pretty = text . prettyShow > > > > prettyShow :: a -> String > > prettyShow = render . pretty > > > > This class should become standard for implementing simple pretty > > printing (instead of the abuse of Show). > > > > Cheers, > > Andreas > > > > > > On 19.10.2014 17:36, Brandon Allbery wrote: > >> On Sun, Oct 19, 2014 at 8:59 AM, Michael Snoyman >> > wrote: > >> > >> I think this really brings up the question of what `Show` should be > >> used for. If the goal is to be simple serialization with `Read` as > >> the inverse[1], then this is clearly a nonsense instance and > >> shouldn't be included. > >> > >> > >> I think I've said before that it would be nice if we had a specific > >> class for debugging displays, given that Read/Show are generally > >> oriented toward serialization. Sadly, this would end up requiring a lot > >> of repetition, since you couldn't sanely fall back on a default Show > >> instance to get a notional Gist (or whatever) instance. > > > > > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From svenpanne at gmail.com Thu Oct 23 10:53:35 2014 From: svenpanne at gmail.com (Sven Panne) Date: Thu, 23 Oct 2014 12:53:35 +0200 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: Probably not very surprising, I'm +1 on disentangling OpenGL and StateVar. :-) Regarding the actual package name and the module name: I don't feel very strongly about that, although inventing yet another package/module name (it would be the third one!) might confuse people even more. There is the StateVar package on Hackage already, and we should have a very good reason to ignore that fact. "I don't like that name" doesn't count IMHO, because this is a personal opinion and doesn't outweigh the confusion introduced by yet another naming scheme. Nevertheless, if that's the price one has to pay to get it into the Haskell Platform, I won't object. Regarding the actual content: I recently added a Functor instance for GettableStateVar (https://github.com/haskell-opengl/OpenGL/commit/3826a63d), but instances for Applicative and Monad should probably be added, too. WDYT? From ollie at ocharles.org.uk Thu Oct 23 12:08:21 2014 From: ollie at ocharles.org.uk (Oliver Charles) Date: Thu, 23 Oct 2014 13:08:21 +0100 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: Sven Panne writes: > Regarding the actual content: I recently added a Functor instance for > GettableStateVar > (https://github.com/haskell-opengl/OpenGL/commit/3826a63d), but > instances for Applicative and Monad should probably be added, too. > WDYT? It's orthogonal to this proposal - but I'd agree with this. Generally, I like to apply the advice for `base` instances: if there's only one logical choice, then we should do it. That said, if this ends up dragging this proposal out, I'd be OK with moving on without these instances. I'll live :) -- ocharles -------------- next part -------------- An HTML attachment was scrubbed... URL: From felipe.lessa at gmail.com Thu Oct 23 17:36:22 2014 From: felipe.lessa at gmail.com (Felipe Lessa) Date: Thu, 23 Oct 2014 15:36:22 -0200 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: <54493C96.50901@gmail.com> On 23-10-2014 08:53, Sven Panne wrote: > Probably not very surprising, I'm +1 on disentangling OpenGL and StateVar. :-) +1 I'm still amazed as how they got retangled in the first place. Cheers, -- Felipe. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From david.feuer at gmail.com Thu Oct 23 17:55:00 2014 From: david.feuer at gmail.com (David Feuer) Date: Thu, 23 Oct 2014 13:55:00 -0400 Subject: Proposal: Add foldrWithIndex and foldlWithIndex to Data.List In-Reply-To: References: <544801E2.2070301@earth.li> <5448163A.40202@earth.li> Message-ID: Yes. Forgive the strange names below. The zip version is 3 times as slow on 7.8.3. I did some horrible hacks to convince 7.8.3 to compile it more like 7.9 would (I don't have Criterion set up for 7.9), and I got it down to only twice as slow. Still, that does not seem so wonderful. {-# LANGUAGE BangPatterns #-} module Main where import Criterion.Main foldlWithIndex :: (Int -> b -> el -> b) -> b -> [el] -> b foldlWithIndex f init xs = foldr go snd xs (0, init) where go x r (!n, a) = r (n+1, f n a x) {-# INLINE zippily #-} -- Taking this out makes it slower zippily :: (Int -> b -> el -> b) -> b -> [el] -> b zippily f init xs = foldl (\acc (!n,x) -> f n acc x) init (zip [0..] xs) sumspecialevens = foldlWithIndex (\n a x -> if even n then a+3*x else a+x) (0::Int) weirdspecialevens=foldlWithIndex (\n a x -> if x `rem` 16 == 0 then a+3*n else a + x) (0::Int) stupidsum = zippily (\n a x -> if even n then a+3*x else a+x) (0::Int) weirdstupidsum=zippily (\n a x -> if x `rem` 16 == 0 then a+3*n else a + x) (0::Int) main = defaultMain $ [ bgroup "useAll" [ bench "fwi" $ nf (\n -> sumspecialevens [1..n]) 1000000 ,bench "zip" $ nf (\n -> stupidsum [1..n]) 1000000 ] ,bgroup "useSome" [ bench "fwi" $ nf (\n -> weirdspecialevens [1..n]) 1000000 ,bench "zip" $ nf (\n -> weirdstupidsum [1..n]) 1000000 ] ] On Thu, Oct 23, 2014 at 1:32 AM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > i hate always asking this question: but do we have an example benchmark > illustrating there being a substantial difference in peformance if > fold(l/r)withIndex is defined directly rather than via the more "naive" > composition? > > On Wed, Oct 22, 2014 at 6:13 PM, David Feuer > wrote: > >> I think the answer is almost certainly no. The zipWith will turn into a >> foldr2, and there's no vaguely sure way of snatching that before it fuses >> with a build form and is lost forever. You'd end up with some very >> complicated rules that only did something useful when the phase of the moon >> was right. I'm pretty sure it's not worth trying. >> On Oct 22, 2014 4:40 PM, "Ganesh Sittampalam" wrote: >> >>> I see, thanks. Could this be done via a rewrite rule from that idiom to >>> an internal implementation function instead? >>> >>> On 22/10/2014 20:19, David Feuer wrote: >>> > Yes, they do. In particular, the zip can only fuse with one of the two >>> > lists so the Ints could be unboxed, or fusion optimizations could >>> happen >>> > with the list folded over, but not both. The fold_WithIndex function >>> can >>> > manage both at once. That said, I think there have been some pretty >>> good >>> > arguments against adding these, or at least against adding them with >>> > these names. >>> > >>> > On Oct 22, 2014 3:13 PM, "Ganesh Sittampalam" >> > > wrote: >>> > >>> > On 16/10/2014 18:14, David Feuer wrote: >>> > >>> > These functions can be lifted pretty much straight out of >>> > Data.Sequence. >>> > In particular, foldrWithIndex makes for a particularly nice >>> > expression >>> > of a fusing findIndices function, as is present in >>> Data.Sequence. >>> > >>> > >>> > Do these do anything better than just adding indicies first with >>> the >>> > standard zip [0..] idiom? >>> > >>> > Cheers, >>> > >>> > Ganesh >>> > >>> > _________________________________________________ >>> > Libraries mailing list >>> > Libraries at haskell.org >>> > http://www.haskell.org/__mailman/listinfo/libraries >>> > >>> > >>> >>> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Thu Oct 23 20:18:42 2014 From: ekmett at gmail.com (Edward Kmett) Date: Thu, 23 Oct 2014 16:18:42 -0400 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: At the risk of bikeshedding things to death: Another option on that front is to just remove the concept of a "GettableStateVar" entirely and substitute 'IO', then 'get' is 'id' or even 'liftIO' and there is no dilemma about whether to use a GettableStateVar or a boring IO action -- and you aren't playing catchup writing instance after instance. type GettableStateVar = IO would just work. ?-Edward -------------- next part -------------- An HTML attachment was scrubbed... URL: From svenpanne at gmail.com Thu Oct 23 20:32:23 2014 From: svenpanne at gmail.com (Sven Panne) Date: Thu, 23 Oct 2014 22:32:23 +0200 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: 2014-10-23 22:18 GMT+02:00 Edward Kmett : > [...] Another option on that front is to just remove the concept of a > "GettableStateVar" entirely and substitute 'IO', [...] -1, for the simple reason that there are probably tons of code out there which might break, just to save writing a few straightforward lines. Furthermore, I like the duality of gettable and settable vars, and this would break it. Let's not discuss things to death again, this is exactly what happened a few years ago. That lead to the exclusion of StateVar from the standard libraries and the subsequent assimilation into OpenGL, the exact thing we're trying to revert. From svenpanne at gmail.com Fri Oct 24 13:13:26 2014 From: svenpanne at gmail.com (Sven Panne) Date: Fri, 24 Oct 2014 15:13:26 +0200 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: FYI: I've updated the standalone version of the package on Hackage: http://hackage.haskell.org/package/StateVar From andreas.abel at ifi.lmu.de Fri Oct 24 16:32:11 2014 From: andreas.abel at ifi.lmu.de (Andreas Abel) Date: Fri, 24 Oct 2014 18:32:11 +0200 Subject: [PROPOSAL] Adding Generics-based DefaultSignature to `deepseq` package In-Reply-To: References: <87h9z4wb5t.fsf@gnu.org> Message-ID: <544A7F0B.7080203@ifi.lmu.de> I am +1 on this change. I was naively under the wrong impression that a simple instance NFData Bla is enough already with the current package. I would be nice if it worked, and the proposal seems to achieve this (at least if one derives Generic). --Andreas On 16.10.2014 21:41, Edward Kmett wrote: > On one hand, the change is a path to a better deepseq that is more correct. > > On the other hand > > 1.) It does change the semantics of existing code. > > 2.) It does cause existing code that works to break if they don't supply > a Generic instance or a manual default. > > Admittedly: > > #1 happens by making it more strict, which is what we want in the case > of NFData, for once. > #2 is something that is easily rectified and makes the resulting code > more robust/useful anyways. Folks who don't want to lean on generics > have the option to just write the rnf x = seq x ()default, so nobody is > being forced to lean on the extension. > > I'm somewhat on the fence about this, because I don't like silent > semantics changes, but as it is only happening by making things more > strict /in the one place in the language/ where that is the very point, > you can consider me weakly +1. > > -Edward > > > On Thu, Oct 16, 2014 at 1:09 PM, Andres L?h > wrote: > > > The Proposal > > ============ > > > > I hereby propose to merge `deepseq-generics`[2] into `deepseq`[1] in > > order to add Generics support to the `NFData` class based on the > > `-XDeriveGenerics` and `-XDefaultSignature` language extensions. > > > > A concrete patch is available for bike-review at [3] > > +1 > > Cheers, > Andres > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From ganesh at earth.li Fri Oct 24 20:59:16 2014 From: ganesh at earth.li (Ganesh Sittampalam) Date: Fri, 24 Oct 2014 21:59:16 +0100 Subject: Proposal: Let OpenGL depend on the StateVar package In-Reply-To: References: Message-ID: <544ABDA4.8010707@earth.li> How about io-state? It seems that adopting this package under any name is better than the status quo, so I'm +0.1 on that, but I'd much prefer a less generic name than StateVar. On 23/10/2014 01:00, Edward Kmett wrote: > imperative-state then? > > On Wed, Oct 22, 2014 at 6:15 PM, Reid Barton > wrote: > > As a point in the package name bike-shedding space, how about > "foreign-state"? Seems suitably descriptive yet general, while also > dissuading casual use with the scary word "foreign". > > Regards, > Reid Barton > > > On Wed, Oct 22, 2014 at 2:23 PM, Edward Kmett > wrote: > > I have no particular objection to renaming the package -- though > it isn't my library. > > We probably would not want to rename the actual types inside the > package though. (Moving them to a namespace that is less > front-and-center, probably shouldn't be a pain point though). If > we bikeshed this to death the proposal may get rejected by the > maintainers as too big of an API change. Having the existing > module just re-export something supplied by an external package > is a small change. > > OpenGL has a very large user base. > > But that said, it isn't actually anything about OpenGL, so much > as how to manipulate a piece of IO-based state that is > gettable/settable in an external API. I'm working with a bunch > of ugly imperative libraries these days where I have such > concerns, OpenEXR, SDL, etc. all expose similar imperative > getter/setter APIs -- none of which have anything in particular > to do with OpenGL, so the name OpenGL-utils is pretty bad, since > it'd be for stuff you can use when you don't or can't depend on > OpenGL, that OpenGL just happens to want too. > > -Edward > > On Wed, Oct 22, 2014 at 1:44 PM, Don Stewart > wrote: > > Previous problems with StateVar apply - name likely to > mislead users into using something they shouldn't. > > If it was named OpenGL-utils no one would mind... > > > On Wednesday, 22 October 2014, Edward Kmett > > wrote: > > We're currently actively working on writing better SDL 2 > bindings in |sdl2|. > > For various reasons, it can't depend on > the |OpenGL| package directly, but it needs a state > variable construction. > > Sadly, not every platform with SDL 2 has OpenGL -- > thanks Microsoft. > > We'd like to depend on the |StateVar| package, but then > we'll get two versions of the notion of > a |StateVar| that conflict. > > By *far* the cleanest option for us moving forward would > be if |OpenGL| switched to using the > external|StateVar| package that you also maintain, then > we could incur a dependency on that. > > I realize that when this was last proposed there was > some pushback from the Haskell Platform, but otherwise > what we're going to start seeing is a profusion of > almost-compatible APIs, which is the very thing that the > Haskell Platform is meant to prevent. > > > This would necessitate adding StateVar to the Haskell > Platform, as OpenGL is in the Haskell Platform. > > > The package is maintained by the same maintainer as the > current OpenGL package. > > > Discussion Period: 2 weeks > > > -Edward Kmett > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > From hvr at gnu.org Sat Oct 25 09:43:58 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Sat, 25 Oct 2014 11:43:58 +0200 Subject: Call-for-help: Add XDGBDS support to `directory` package Message-ID: <874mustrfl.fsf@gnu.org> Hello *, I'd like to invite everyone with knowledge of the XDG Base Directory Specification[1] to contribute to https://github.com/haskell/directory/issues/6 >From what I gathered, it appears to me that adhering to the XDGBD Spec (on Linux at least) is desirable and "strongly encouraged" by Linux distributions[2], so I think this ought to be implemented sooner rather than later (maybe even in time to be part of GHC 7.10.1) This issue was originally filed against GHC, since it affects the location of the `~/.ghc` folder (and fwiw this would also affect cabal's `~/.cabal` folder location). Thanks, hvr [1]: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html [2]: https://wiki.debian.org/XDGBaseDirectorySpecification From david.feuer at gmail.com Mon Oct 27 23:04:53 2014 From: david.feuer at gmail.com (David Feuer) Date: Mon, 27 Oct 2014 19:04:53 -0400 Subject: Proposal: Add a strictly accumulating scanl' to Data.List In-Reply-To: References: Message-ID: There's been no response to this so far, and I'd like to get it for 7.10.1. Any opinions? Joachim Breitner wrote, in https://ghc.haskell.org/trac/ghc/ticket/9345#comment:6, a strictly accumulating version of scanl, to be named scanl'. I was initially concerned about its safety for fusion, but am now convinced of its correctness and believe it should be added to Data.List. scanl' :: (b -> a -> b) -> b -> [a] -> [b] scanl' f a bs = build $ \c n -> a `seq` a `c` foldr (\b g x -> (let b' = f x b in b' `seq` (b' `c` g b'))) (\b -> b `seq` n) bs a -------------- next part -------------- An HTML attachment was scrubbed... URL: From mail at joachim-breitner.de Tue Oct 28 09:33:43 2014 From: mail at joachim-breitner.de (Joachim Breitner) Date: Tue, 28 Oct 2014 10:33:43 +0100 Subject: Proposal: Add a strictly accumulating scanl' to Data.List In-Reply-To: References: Message-ID: <1414488823.1418.2.camel@joachim-breitner.de> Hi, Am Montag, den 27.10.2014, 19:04 -0400 schrieb David Feuer: > There's been no response to this so far, and I'd like to get it for > 7.10.1. Any opinions? I?m fine with the addition. (Generally, complete silence can be taken as mild agreement from everyone :-)) 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 felipe.lessa at gmail.com Tue Oct 28 12:50:02 2014 From: felipe.lessa at gmail.com (Felipe Lessa) Date: Tue, 28 Oct 2014 10:50:02 -0200 Subject: Proposal: Add a strictly accumulating scanl' to Data.List In-Reply-To: <1414488823.1418.2.camel@joachim-breitner.de> References: <1414488823.1418.2.camel@joachim-breitner.de> Message-ID: <723BBA04-CBA3-433E-8A08-C6EEABAE3C46@gmail.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Me too. It just bothers me a bit that the 4th line's call to seq uses parenthesis while the 3rd's doesn't :). Em 28 de outubro de 2014 07:33:43 BRST, Joachim Breitner escreveu: >Hi, > > >Am Montag, den 27.10.2014, 19:04 -0400 schrieb David Feuer: >> There's been no response to this so far, and I'd like to get it for >> 7.10.1. Any opinions? > >I?m fine with the addition. > >(Generally, complete silence can be taken as mild agreement from >everyone :-)) > >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://www.haskell.org/mailman/listinfo/libraries - -- Felipe. -----BEGIN PGP SIGNATURE----- iQJXBAEBCABBOhxGZWxpcGUgQWxtZWlkYSBMZXNzYSAobWV0ZWZpY2hhKSA8ZmVs aXBlLmxlc3NhQGdtYWlsLmNvbT4FAlRPkPoACgkQp2TRhD6WaClchxAA1uSrpFB7 eGQT+4+gTot2GGxU2JrFQSLhOthFqp/KTdK2sCU/INGGYTCoLKx5/JYt30q+1npG DGt0cgQ/5m9FEP3yl4t9/bSBj3x0pARu6DUeYNnSHX3l070/qsO9JpmvgpVtQz0N xokMPGm3BMbjJyC1+9reFwcm/o7QH3bCdoRtlajJjn253bERHNwROht3UfAYWBYp YdUcvy81QV+Tpbwk/Rj/8sGEFNAYihBJycJnRs1ZIFzY5KKw3wtINlLj8Jj8BICS KhqhBT6ZuII76+roOrm2T42p3N8GGAM7n7uIP8h3HamPNnG9B+Ur4pFrMZNc0Fvw NZN5+gilcQTCSo4NmpxtFOFvre1CYFzoXKIZhUr584F8HiI9LrN8+oF/q5lWd54V gPEmKj1yGDgAbxL6iDNznnYuEp7ulWPdh5sWVF3QsqRaCJ0HBVZthD6K9Xz0YELn zEDQELEAag2btP/uTtqtTyR5wi27EYojUi4jpGSXRTDkKRByLKgBV+XxRoOTWpTF P4h0QgJ967q/svANdSlXL3/8he65xMmp5dgPBZEjlBGbcchGObsEUiQLEPZYqh6f EUFfDWvt2MijTLKAo14h0o0fEGnXpSd2WCcGLygd2xUn4Y7piYwe15g+/Q314DQz 1h3U9MdJ8kYy1pINEtAgW3CCg6t/2/S57mc= =pwBX -----END PGP SIGNATURE----- From nikita.y.volkov at mail.ru Tue Oct 28 15:02:59 2014 From: nikita.y.volkov at mail.ru (Nikita Volkov) Date: Tue, 28 Oct 2014 19:02:59 +0400 Subject: ANNOUNCE: Hasql: A minimalistic general high level API for relational databases Message-ID: This library takes a mission of upgrading the experience of dealing with relational databases in Haskell. It?s robust, it?s API is very concise, yet it?s packed with powerful features like the following: - An abstraction over transactions, which provides an automated resolution of conflicts. The API ensures that you?re only able to perform a specific set of actions in the transaction context, which allows Hasql to safely resolve conflicting transactions by automatically retrying them. This is much inspired by STM and ST. - Support for cursors. Allows to fetch virtually limitless result sets in a constant memory using streaming. - Employment of prepared statements. Every statement you emit gets prepared and cached. This raises the performance of the backend. - Automated management of resources related to connections, transactions and cursors. - A built-in connections pool. - Type-level generation of templates. You just can?t write a statement with an incorrect number of placeholders. - Mapping to any types actually supported by the backend. For a basic tutorial and a demonstration please visit the following link: https://github.com/nikita-volkov/hasql/blob/master/demo/Main.hs Also please join the main discussion thread accompanying the release: http://www.reddit.com/r/haskell/comments/2kkhgo/announce_hasql_a_minimalistic_general_high_level/ -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Tue Oct 28 23:43:55 2014 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 29 Oct 2014 01:43:55 +0200 Subject: Discussion: adding displayException to Exception class Message-ID: I don't want to make a format proposal yet, just open up discussion on an issue, and see how others feel about it. As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read). However, there's at least one use case in base which explicitly uses Show for non-serialization purposes: the Exception class. All instances of Exception are required to have an instance of Show, but there's no way to actually serialize exceptions generally[2]. So by construction and by practice, the Show instance for Exception is used exclusively for the latter two categories I mentioned (debug info and user-friendly data display). As a result of that, it's quite common[3] to define a Show instance for exception types that is *not* serializable, but rather user friendly. This however seems to contradict what is accepted as good practice in general. I have a possible solution that I'd like to propose as a strawman: add a new method to the Exception typeclass: displayException :: e -> String displayException = show The name is up for debate, but I chose `display` since it seems to already be used elsewhere for user-friendly output. Other possible choices are showException or prettyException. The default implementation will reuse the Show instance, so no user code will be broken by this[4]. In the short term, the only other change I'd recommend is that the default exception handler use `displayException` instead of `show` for printing uncaught exceptions. Longer term, after deprecation cycles, we could consider removing the Show superclass from Exception. Again, this isn't a real proposal (yet), I'm more interested now in what people think about such a change. Michael [1] http://www.haskell.org/pipermail/libraries/2014-October/023957.html [2] Both due to how extensible exceptions work, and due to the lack of a Read superclass. [3] This discussion started when Chris Done and I were working with the tar package, which defines custom renderings for FormatError. I've implemented this same technique in some of my libraries, and I'm sure there are many other examples on Hackage. [4] Barring the standard issue of new identifiers clashing with identifiers defined locally. -------------- next part -------------- An HTML attachment was scrubbed... URL: From felipe.lessa at gmail.com Wed Oct 29 00:09:36 2014 From: felipe.lessa at gmail.com (Felipe Lessa) Date: Tue, 28 Oct 2014 22:09:36 -0200 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: Message-ID: <54503040.7070301@gmail.com> I like the proposal. I think, though, that it needs more motivation: "is it just to be consistent with most other Show instances?" Personally, I think it will be nice to be able to quickly identify the constructor of the exception. Currently one has Google for the error message and hope for the best. Cheers, -- Felipe. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: From michael at snoyman.com Wed Oct 29 00:13:25 2014 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 29 Oct 2014 02:13:25 +0200 Subject: Discussion: adding displayException to Exception class In-Reply-To: <54503040.7070301@gmail.com> References: <54503040.7070301@gmail.com> Message-ID: Thank you for pointing that out. As it happens, that's the exact conversation Chris and I had which led to this email ;). On Wed, Oct 29, 2014 at 2:09 AM, Felipe Lessa wrote: > I like the proposal. I think, though, that it needs more motivation: > "is it just to be consistent with most other Show instances?" > > Personally, I think it will be nice to be able to quickly identify the > constructor of the exception. Currently one has Google for the error > message and hope for the best. > > Cheers, > > -- > Felipe. > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jwlato at gmail.com Wed Oct 29 00:17:50 2014 From: jwlato at gmail.com (John Lato) Date: Wed, 29 Oct 2014 08:17:50 +0800 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: Message-ID: I guess I'm moderately sympathetic to the idea, although if I'm completely honest it seems like a lot of make-work for little tangible benefit. It would make more sense to me if there were also a push to make Read a superclass of Exception, in which case Show should clearly be for serialization (it is possible to make this work for existentially-quantified data, but it would require manual instances). It would make even more sense if Show were meant to be some sort of user-readable string, and we used a different class (paired with Read) for serialization. Unfortunately that ship sailed long ago. John L. On Wed, Oct 29, 2014 at 7:43 AM, Michael Snoyman wrote: > I don't want to make a format proposal yet, just open up discussion on an > issue, and see how others feel about it. > > As I recently commented on this list[1], the Show typeclass is overloaded > with multiple meanings (serialization, debug info, and user-friendly data > display). The general consensus seems to be that the official semantics for > Show should be for serialization (as paired up with Read). > > However, there's at least one use case in base which explicitly uses Show > for non-serialization purposes: the Exception class. All instances of > Exception are required to have an instance of Show, but there's no way to > actually serialize exceptions generally[2]. So by construction and by > practice, the Show instance for Exception is used exclusively for the > latter two categories I mentioned (debug info and user-friendly data > display). > > As a result of that, it's quite common[3] to define a Show instance for > exception types that is *not* serializable, but rather user friendly. This > however seems to contradict what is accepted as good practice in general. > > > I have a possible solution that I'd like to propose as a strawman: add a > new method to the Exception typeclass: > > displayException :: e -> String > displayException = show > > The name is up for debate, but I chose `display` since it seems to already > be used elsewhere for user-friendly output. Other possible choices are > showException or prettyException. The default implementation will reuse the > Show instance, so no user code will be broken by this[4]. > > In the short term, the only other change I'd recommend is that the default > exception handler use `displayException` instead of `show` for printing > uncaught exceptions. Longer term, after deprecation cycles, we could > consider removing the Show superclass from Exception. > > Again, this isn't a real proposal (yet), I'm more interested now in what > people think about such a change. > > Michael > > [1] http://www.haskell.org/pipermail/libraries/2014-October/023957.html > [2] Both due to how extensible exceptions work, and due to the lack of a > Read superclass. > [3] This discussion started when Chris Done and I were working with the > tar package, which defines custom renderings for FormatError. I've > implemented this same technique in some of my libraries, and I'm sure there > are many other examples on Hackage. > [4] Barring the standard issue of new identifiers clashing with > identifiers defined locally. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Wed Oct 29 00:26:21 2014 From: david.feuer at gmail.com (David Feuer) Date: Tue, 28 Oct 2014 20:26:21 -0400 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: Message-ID: On Tue, Oct 28, 2014 at 8:17 PM, John Lato wrote: > I guess I'm moderately sympathetic to the idea, although if I'm completely > honest it seems like a lot of make-work for little tangible benefit. > > It would make more sense to me if there were also a push to make Read a > superclass of Exception, in which case Show should clearly be for > serialization (it is possible to make this work for > existentially-quantified data, but it would require manual instances). > > It would make even more sense if Show were meant to be some sort of > user-readable string, and we used a different class (paired with Read) for > serialization. Unfortunately that ship sailed long ago. > > Isn't there at least one prettyprinting package out there, with some sort of prettyprintable class? Could we steal it? David -------------- next part -------------- An HTML attachment was scrubbed... URL: From sol at typeful.net Wed Oct 29 01:52:28 2014 From: sol at typeful.net (Simon Hengel) Date: Wed, 29 Oct 2014 09:52:28 +0800 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: Message-ID: <20141029015228.GA10868@x200> > It would make more sense to me if there were also a push to make Read > a superclass of Exception Considering that IOException can include a Handle, can this possibly work? Cheers, Simon From jwlato at gmail.com Wed Oct 29 02:00:04 2014 From: jwlato at gmail.com (John Lato) Date: Wed, 29 Oct 2014 10:00:04 +0800 Subject: Discussion: adding displayException to Exception class In-Reply-To: <20141029015228.GA10868@x200> References: <20141029015228.GA10868@x200> Message-ID: On Wed, Oct 29, 2014 at 9:52 AM, Simon Hengel wrote: > > It would make more sense to me if there were also a push to make Read > > a superclass of Exception > > Considering that IOException can include a Handle, can this possibly > work? > > Cheers, > Simon > What does it mean to try to make Show a serializer if the deserialization stage can't possibly work? -------------- next part -------------- An HTML attachment was scrubbed... URL: From sol at typeful.net Wed Oct 29 02:22:02 2014 From: sol at typeful.net (Simon Hengel) Date: Wed, 29 Oct 2014 10:22:02 +0800 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <54503040.7070301@gmail.com> Message-ID: <20141029022202.GA9169@x200> Hi Michael, > > Personally, I think it will be nice to be able to quickly identify the > > constructor of the exception. Currently one has Google for the error > > message and hope for the best. > > Thank you for pointing that out. As it happens, that's the exact > conversation Chris and I had which led to this email ;). Same thought here, one of my main complaints about the current state of exceptions is that the default exception handler gives you no hint about the type of uncaught exceptions. For me uncaught exceptions are a programming error and I want output that helps me as a programmer to fix that programming error. I don't care about "user-friendly data display" here. I think given the nature of hierarchical exceptions there is currently no generic way to show the exception type if the exception is at depth < 1 in the tree (for uncaught exceptions in Hspec I use the code at [1], which is better than using show but still not ideal). For this reason I *always* derive the Show instance if I define an exception type + I would prefer if Show instances for other exceptions would be derived, too (where possible). Would this proposal address this issue? How exactly? Could we just fix the (in my perspective) "broken" Show instances for standard exceptions instead? Cheers, Simon [1] https://github.com/hspec/hspec/blob/03651daf5b9eee4ca9e3c3941743519cda4768ab/hspec-core/src/Test/Hspec/Util.hs#L23 From michael at snoyman.com Wed Oct 29 02:33:25 2014 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 29 Oct 2014 04:33:25 +0200 Subject: Discussion: adding displayException to Exception class In-Reply-To: <20141029022202.GA9169@x200> References: <54503040.7070301@gmail.com> <20141029022202.GA9169@x200> Message-ID: On Wed, Oct 29, 2014 at 4:22 AM, Simon Hengel wrote: > Hi Michael, > > > > Personally, I think it will be nice to be able to quickly identify the > > > constructor of the exception. Currently one has Google for the error > > > message and hope for the best. > > > > Thank you for pointing that out. As it happens, that's the exact > > conversation Chris and I had which led to this email ;). > > Same thought here, one of my main complaints about the current state of > exceptions is that the default exception handler gives you no hint about > the type of uncaught exceptions. > > For me uncaught exceptions are a programming error and I want output > that helps me as a programmer to fix that programming error. I don't > care about "user-friendly data display" here. > > I think given the nature of hierarchical exceptions there is currently > no generic way to show the exception type if the exception is at depth < > 1 in the tree (for uncaught exceptions in Hspec I use the code at [1], > which is better than using show but still not ideal). > > For this reason I *always* derive the Show instance if I define an > exception type + I would prefer if Show instances for other exceptions > would be derived, too (where possible). > > Would this proposal address this issue? How exactly? Could we just fix > the (in my perspective) "broken" Show instances for standard exceptions > instead? > > > > We're coming from opposite ends on this one. I'm often writing user-facing applications, where a failure message of `FailedConection "www.example.com" 80` is bad, and "Unable to make a connection to www.example.com on port 80" is good. Both user-friendly and programmer-friendly display make sense, they're just different use cases. And currently, they're shoe-horned into the same `Show` instance. As long as we're all in agreement that I'm not making a real proposal, here's a solution to the problem: more methods! What about adding: displayException :: e -> String rawException :: e -> String -- meant to be the "serialized" version like derived Show instances verboseException :: e -> String -- include module the type is defined in, its package, data type, etc We can give all of these default implementations as well. The downside is that every possible usecase someone comes up with needs to go in Exception, which doesn't scale past a certain point. The question then becomes: have we already identified all of the use cases we care about? A completely different approach that might be better for your use case *and* might be useful in other cases would be to keep a stack of the `TypeRep`s we converted through when creating the SomeException. However, that would require a breaking change to SomeException, which I really *don't* want to propose. Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From jeremy at n-heptane.com Wed Oct 29 02:55:06 2014 From: jeremy at n-heptane.com (Jeremy Shaw) Date: Tue, 28 Oct 2014 21:55:06 -0500 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: Message-ID: On Tue, Oct 28, 2014 at 6:43 PM, Michael Snoyman wrote: > As I recently commented on this list[1], the Show typeclass is overloaded > with multiple meanings (serialization, debug info, and user-friendly data > display). The general consensus seems to be that the official semantics for > Show should be for serialization (as paired up with Read). A bit off topic but, I think the semantics of Show/Read should actually be even stronger. Serializing to a String is a bit pointless -- things like Binary, Cereal, SafeCopy etc are much more suited for 'serialization'. It seems to me that Show and Read are really closer to ShowExpr and ReadExpr in many cases. The idea being that you can show a value, copy and paste that string into GHCi and get back your original value. For many show instances this holds true. Though clearly not all. I'd love to see: 1. Show/Read really be ShowExpr/ReadExpr 2. Binary 3. SafeCopy (like binary, but versioned with migration) 4. Pretty Of course, that opens the can of worms -- why not HTML instances, Markdown instances, etc. This is probably more a proposal for something like Idris where changes like this are still viable ;) - jeremy From jwlato at gmail.com Wed Oct 29 02:57:46 2014 From: jwlato at gmail.com (John Lato) Date: Wed, 29 Oct 2014 10:57:46 +0800 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <54503040.7070301@gmail.com> <20141029022202.GA9169@x200> Message-ID: On Wed, Oct 29, 2014 at 10:33 AM, Michael Snoyman wrote: > > A completely different approach that might be better for your use case > *and* might be useful in other cases would be to keep a stack of the > `TypeRep`s we converted through when creating the SomeException. However, > that would require a breaking change to SomeException, which I really > *don't* want to propose. > We already keep all the TypeReps, they just aren't generically accessible. If we added a function to the Exception class like typeRepStack :: a -> [TypeRep] it should work. A more-or-less sensible default is typeRepStack a = [typeOf a], which would work for all terminal exception types. A mid-level type in a hierarchy would need a different value though, something like typeRepStack se@(SomeException e) = typeOf se : typeRepStack e -------------- next part -------------- An HTML attachment was scrubbed... URL: From roma at ro-che.info Wed Oct 29 03:09:29 2014 From: roma at ro-che.info (Roman Cheplyaka) Date: Wed, 29 Oct 2014 05:09:29 +0200 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <54503040.7070301@gmail.com> <20141029022202.GA9169@x200> Message-ID: <54505A69.6030702@ro-che.info> +1 to having separate methods for Show-like and human-friendly displaying of exceptions. Not sure if we need rawException ? just using Show superclass in this case seems appropriate. On 29/10/14 04:33, Michael Snoyman wrote: > On Wed, Oct 29, 2014 at 4:22 AM, Simon Hengel wrote: > >> Hi Michael, >> >>>> Personally, I think it will be nice to be able to quickly identify the >>>> constructor of the exception. Currently one has Google for the error >>>> message and hope for the best. >>> >>> Thank you for pointing that out. As it happens, that's the exact >>> conversation Chris and I had which led to this email ;). >> >> Same thought here, one of my main complaints about the current state of >> exceptions is that the default exception handler gives you no hint about >> the type of uncaught exceptions. >> >> For me uncaught exceptions are a programming error and I want output >> that helps me as a programmer to fix that programming error. I don't >> care about "user-friendly data display" here. >> >> I think given the nature of hierarchical exceptions there is currently >> no generic way to show the exception type if the exception is at depth < >> 1 in the tree (for uncaught exceptions in Hspec I use the code at [1], >> which is better than using show but still not ideal). >> >> For this reason I *always* derive the Show instance if I define an >> exception type + I would prefer if Show instances for other exceptions >> would be derived, too (where possible). >> >> Would this proposal address this issue? How exactly? Could we just fix >> the (in my perspective) "broken" Show instances for standard exceptions >> instead? >> >> >> >> > We're coming from opposite ends on this one. I'm often writing user-facing > applications, where a failure message of `FailedConection "www.example.com" > 80` is bad, and "Unable to make a connection to www.example.com on port 80" > is good. Both user-friendly and programmer-friendly display make sense, > they're just different use cases. And currently, they're shoe-horned into > the same `Show` instance. > > As long as we're all in agreement that I'm not making a real proposal, > here's a solution to the problem: more methods! What about adding: > > displayException :: e -> String > rawException :: e -> String -- meant to be the "serialized" version > like derived Show instances > verboseException :: e -> String -- include module the type is defined > in, its package, data type, etc > > We can give all of these default implementations as well. The downside is > that every possible usecase someone comes up with needs to go in Exception, > which doesn't scale past a certain point. The question then becomes: have > we already identified all of the use cases we care about? > > A completely different approach that might be better for your use case > *and* might be useful in other cases would be to keep a stack of the > `TypeRep`s we converted through when creating the SomeException. However, > that would require a breaking change to SomeException, which I really > *don't* want to propose. > > Michael From sol at typeful.net Wed Oct 29 03:55:39 2014 From: sol at typeful.net (Simon Hengel) Date: Wed, 29 Oct 2014 11:55:39 +0800 Subject: Discussion: adding displayException to Exception class In-Reply-To: <54505A69.6030702@ro-che.info> References: <54503040.7070301@gmail.com> <20141029022202.GA9169@x200> <54505A69.6030702@ro-che.info> Message-ID: <20141029035539.GA7076@x200> > +1 to having separate methods for Show-like and human-friendly > displaying of exceptions. Yes, I agree. I've done a quick comparison on how Ruby/Python/Java convert exceptions to strings: https://github.com/sol/exceptions-by-language Note that in Ruby/Python there is a distinction between "getting a representation of a value" (inspect/repr) and "converting a value into a string" (to_s/str). In Haskell we only have show, which is akin to inspect/repr. All of them still use a different formatting in the default handler, so it may make still sense to make the full exception type accessible. But that could be a different discussion. Cheers, Simon From hvr at gnu.org Wed Oct 29 08:39:07 2014 From: hvr at gnu.org (Herbert Valerio Riedel) Date: Wed, 29 Oct 2014 09:39:07 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: (Michael Snoyman's message of "Wed, 29 Oct 2014 01:43:55 +0200") References: Message-ID: <87ioj346dw.fsf@gnu.org> Hi Michael, On 2014-10-29 at 00:43:55 +0100, Michael Snoyman wrote: > I don't want to make a format proposal yet, just open up discussion on an > issue, and see how others feel about it. > > As I recently commented on this list[1], the Show typeclass is overloaded > with multiple meanings (serialization, debug info, and user-friendly data > display). The general consensus seems to be that the official semantics for > Show should be for serialization (as paired up with Read). [...] > I have a possible solution that I'd like to propose as a strawman: add a > new method to the Exception typeclass: > > displayException :: e -> String > displayException = show As we're having the general problem of 'Show' being abused for pretty-printing, why not rather standardise on a pretty-show/printing typeclass that would not be limited to Exceptions? What am I missing? Cheers, hvr From simonpj at microsoft.com Wed Oct 29 08:45:05 2014 From: simonpj at microsoft.com (Simon Peyton Jones) Date: Wed, 29 Oct 2014 08:45:05 +0000 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: Message-ID: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read). Really? My instinct is otherwise: to use Show for human-readable display, and Binary for serialisation. Show/Read is a terribly inefficient serialisation format; as soon as you want to do it for real you end up with Binary anyway. And Show is already well established for human-readable purposes ? that was one of its primary original purposes. Simon From: Libraries [mailto:libraries-bounces at haskell.org] On Behalf Of Michael Snoyman Sent: 28 October 2014 23:44 To: libraries; Christopher Done Subject: Discussion: adding displayException to Exception class I don't want to make a format proposal yet, just open up discussion on an issue, and see how others feel about it. As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read). However, there's at least one use case in base which explicitly uses Show for non-serialization purposes: the Exception class. All instances of Exception are required to have an instance of Show, but there's no way to actually serialize exceptions generally[2]. So by construction and by practice, the Show instance for Exception is used exclusively for the latter two categories I mentioned (debug info and user-friendly data display). As a result of that, it's quite common[3] to define a Show instance for exception types that is *not* serializable, but rather user friendly. This however seems to contradict what is accepted as good practice in general. I have a possible solution that I'd like to propose as a strawman: add a new method to the Exception typeclass: displayException :: e -> String displayException = show The name is up for debate, but I chose `display` since it seems to already be used elsewhere for user-friendly output. Other possible choices are showException or prettyException. The default implementation will reuse the Show instance, so no user code will be broken by this[4]. In the short term, the only other change I'd recommend is that the default exception handler use `displayException` instead of `show` for printing uncaught exceptions. Longer term, after deprecation cycles, we could consider removing the Show superclass from Exception. Again, this isn't a real proposal (yet), I'm more interested now in what people think about such a change. Michael [1] http://www.haskell.org/pipermail/libraries/2014-October/023957.html [2] Both due to how extensible exceptions work, and due to the lack of a Read superclass. [3] This discussion started when Chris Done and I were working with the tar package, which defines custom renderings for FormatError. I've implemented this same technique in some of my libraries, and I'm sure there are many other examples on Hackage. [4] Barring the standard issue of new identifiers clashing with identifiers defined locally. -------------- next part -------------- An HTML attachment was scrubbed... URL: From thomasmiedema at gmail.com Wed Oct 29 10:59:22 2014 From: thomasmiedema at gmail.com (Thomas Miedema) Date: Wed, 29 Oct 2014 11:59:22 +0100 Subject: Proposal: make nubBy obey the 98 report semantics In-Reply-To: <5422894D.2000101@chalmers.se> References: <5422894D.2000101@chalmers.se> Message-ID: This proposal is now accepted. Soon in a GHC near you. Andreas and Dan: thank you for your comments. You are correct I guess that the current implementation does not technically violate the report specification, and that the behavior of nubBy is only properly defined when used with an equivalence relation. Some people asked for this change, so I'd like to make it and close those tickets. On Wed, Sep 24, 2014 at 11:05 AM, Andreas Abel wrote: > Same indifference here, what does "remove duplicates according to relation > R" mean intuitively if R is not an equivalence relation? > > (nub and nubBy with their quadratic complexity are anyway a wart. These > names should ideally be used for versions that only work for lists over > ordered type, so that one can give an implementation with a sensible > complexity.) > > But do if you must. > > On 24.09.2014 01:45, Dan Doel wrote: > >> nub and nubBy already obey the semantics of the Haskell 2010 report, >> which only specifies the behavior when you pass it an "equality test," >> presumably an equivalence relation. >> >> The Haskell 98 report similarly specified nubBy as assuming the function >> passed in defined an equivalence. So the current definition is not >> actually in violation of that spec, either. Rather, 'nubBy (<)' is >> calling the function with an invalid argument. >> >> I'm ambivalent about whether this gets 'fixed', but it is technically >> not a bug (or, the only definitive error is that the comment doesn't >> match the implementation). >> >> -- Dan >> >> On Tue, Sep 23, 2014 at 5:45 PM, Thomas Miedema > > wrote: >> >> The implementation of nubBy in Data.List is as follows, where >> USE_REPORT_PRELUDE refers to [1]: >> >> #ifdef USE_REPORT_PRELUDE >> nubBy eq [] = [] >> nubBy eq (x:xs) = x : nubBy eq (filter (\ y -> not (eq >> x y)) xs) >> #else >> nubBy eq l = nubBy' l [] >> where >> nubBy' [] _ = [] >> nubBy' (y:ys) xs >> | elem_by eq y xs = nubBy' ys xs >> | otherwise = y : nubBy' ys (y:xs) >> >> -- Not exported: >> -- Note that we keep the call to `eq` with arguments in the >> -- same order as in the reference implementation >> -- 'xs' is the list of things we've seen so far, >> -- 'y' is the potential new element >> elem_by :: (a -> a -> Bool) -> a -> [a] -> Bool >> elem_by _ _ [] = False >> elem_by eq y (x:xs) = y `eq` x || elem_by eq y xs >> #endif >> >> That comment is actually not correct [2], and the report version and >> the base >> version don't have the same semantics when used on asymmetric >> relations: >> >> MyReportPrelude> nubBy (<) [1] >> [1] >> >> Data.List> nubBy (<) [1,2] >> [1,2] >> >> ## Proposal >> Make nubBy and nub obey the report semantics by swapping the >> arguments to >> `eq` in elem_by, and defining nub as nubBy (==). This is the 'still >> easy' >> variant from [3]. >> >> ## Motivation >> The Report's order is more sensible, since the parameters to the >> relation stay >> in the left-to-right order in which they occurred in the list. See >> [4,5] for >> user bug reports. >> >> Discussion period: 2 weeks >> Code review: https://phabricator.haskell.org/D238 >> >> [1] https://www.haskell.org/onlinereport/list.html#sect17.6 >> [2] https://ghc.haskell.org/trac/ghc/ticket/2528 >> [3] https://ghc.haskell.org/trac/ghc/ticket/7913#comment:3 >> [4] https://ghc.haskell.org/trac/ghc/ticket/3280 >> [5] https://ghc.haskell.org/trac/ghc/ticket/7913 >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > > -- > Andreas Abel <>< Du bist der geliebte Mensch. > > Department of Computer Science and Engineering > Chalmers and Gothenburg University, Sweden > > andreas.abel at gu.se > http://www2.tcs.ifi.lmu.de/~abel/ > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Wed Oct 29 10:58:56 2014 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 29 Oct 2014 12:58:56 +0200 Subject: Discussion: adding displayException to Exception class In-Reply-To: <87ioj346dw.fsf@gnu.org> References: <87ioj346dw.fsf@gnu.org> Message-ID: On Wed, Oct 29, 2014 at 10:39 AM, Herbert Valerio Riedel wrote: > Hi Michael, > > On 2014-10-29 at 00:43:55 +0100, Michael Snoyman wrote: > > I don't want to make a format proposal yet, just open up discussion on an > > issue, and see how others feel about it. > > > > As I recently commented on this list[1], the Show typeclass is overloaded > > with multiple meanings (serialization, debug info, and user-friendly data > > display). The general consensus seems to be that the official semantics > for > > Show should be for serialization (as paired up with Read). > > [...] > > > I have a possible solution that I'd like to propose as a strawman: add a > > new method to the Exception typeclass: > > > > displayException :: e -> String > > displayException = show > > As we're having the general problem of 'Show' being abused for > pretty-printing, why not rather standardise on a pretty-show/printing > typeclass that would not be limited to Exceptions? What am I missing? > > The downside to that is that it introduces a breaking change, whereas this proposal does not. If we *do* want to standardize on a pretty-printing typeclass, I think the right way forward (though somewhat painful) is: Release X: Introduce the pretty-printing typeclass, add displayException with default implementation of Show, do not otherwise change Exception. Release X+1: Add new typeclass as a superclass of Exception. Release X+2: Switch default implementation of displayException to the pretty-show. Release X+3: Remove Show as a superclass. Maybe some of those steps can be combined, I'm not certain. Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Wed Oct 29 11:02:11 2014 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 29 Oct 2014 13:02:11 +0200 Subject: Discussion: adding displayException to Exception class In-Reply-To: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones wrote: > As I recently commented on this list[1], the Show typeclass is > overloaded with multiple meanings (serialization, debug info, and > user-friendly data display). The general consensus seems to be that the > official semantics for Show should be for serialization (as paired up with > Read). > > > > Really? My instinct is otherwise: *to use Show for human-readable > display, and Binary for serialisation*. Show/Read is a terribly > inefficient serialisation format; as soon as you want to do it for real you > end up with Binary anyway. And Show is already well established for > human-readable purposes ? that was one of its primary original purposes. > > > > Simon > > My weak vote in that thread went towards Show for human-readable display, but there was some quite harsh objection to that position. In this thread too you can see people wanting a direct encoding of types which can be copy-pasted into a Haskell source file. Personally, I don't see much need for that, and especially given the new ability to essentially auto-derive Binary instances (via Generic), Show/Read serialization seems fairly pointless. Nonetheless, making a proposal that doesn't enforce a changed semantics on the Show typeclass seems like the path of least resistance. If others want to jump back into the previous topic and try to hammer down the ideal usage of the Show typeclass, I'm happy to participate in that discussion too. Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From simonpj at microsoft.com Wed Oct 29 11:18:12 2014 From: simonpj at microsoft.com (Simon Peyton Jones) Date: Wed, 29 Oct 2014 11:18:12 +0000 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> If people want Show to generate something that can be copy/pasted into a Haskell source file, that?s a legitimate position. But please let?s not call it ?serialisation?! So we have: 1. Serialisation (use Binary) 2. Copy-pasteable into Haskell source file, but not necessarily human-readable (Show) 3. Human readable (Display) It?s clearly a library-design issue whether (2) and (3) are worth separating. More classes, more code, but perhaps more expressiveness. What does the core libraries committee think? Personally I don?t see (2) as particularly important, but my opinion counts for little since I?m not a library author. Simon From: Libraries [mailto:libraries-bounces at haskell.org] On Behalf Of Michael Snoyman Sent: 29 October 2014 11:02 To: Simon Peyton Jones Cc: libraries Subject: Re: Discussion: adding displayException to Exception class On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones > wrote: As I recently commented on this list[1], the Show typeclass is overloaded with multiple meanings (serialization, debug info, and user-friendly data display). The general consensus seems to be that the official semantics for Show should be for serialization (as paired up with Read). Really? My instinct is otherwise: to use Show for human-readable display, and Binary for serialisation. Show/Read is a terribly inefficient serialisation format; as soon as you want to do it for real you end up with Binary anyway. And Show is already well established for human-readable purposes ? that was one of its primary original purposes. Simon My weak vote in that thread went towards Show for human-readable display, but there was some quite harsh objection to that position. In this thread too you can see people wanting a direct encoding of types which can be copy-pasted into a Haskell source file. Personally, I don't see much need for that, and especially given the new ability to essentially auto-derive Binary instances (via Generic), Show/Read serialization seems fairly pointless. Nonetheless, making a proposal that doesn't enforce a changed semantics on the Show typeclass seems like the path of least resistance. If others want to jump back into the previous topic and try to hammer down the ideal usage of the Show typeclass, I'm happy to participate in that discussion too. Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From jake.mcarthur at gmail.com Wed Oct 29 11:19:46 2014 From: jake.mcarthur at gmail.com (Jake McArthur) Date: Wed, 29 Oct 2014 07:19:46 -0400 Subject: Proposal: make nubBy obey the 98 report semantics In-Reply-To: <5422894D.2000101@chalmers.se> References: <5422894D.2000101@chalmers.se> Message-ID: I disagree that it's a wart. The wart is that we don't *also* have an Ord version. nub/nubBy have two great properties. (1) They only require Eq. (2) They are lazier than their Ord-using counterparts. On Sep 24, 2014 5:05 AM, "Andreas Abel" wrote: > Same indifference here, what does "remove duplicates according to relation > R" mean intuitively if R is not an equivalence relation? > > (nub and nubBy with their quadratic complexity are anyway a wart. These > names should ideally be used for versions that only work for lists over > ordered type, so that one can give an implementation with a sensible > complexity.) > > But do if you must. > > On 24.09.2014 01:45, Dan Doel wrote: > >> nub and nubBy already obey the semantics of the Haskell 2010 report, >> which only specifies the behavior when you pass it an "equality test," >> presumably an equivalence relation. >> >> The Haskell 98 report similarly specified nubBy as assuming the function >> passed in defined an equivalence. So the current definition is not >> actually in violation of that spec, either. Rather, 'nubBy (<)' is >> calling the function with an invalid argument. >> >> I'm ambivalent about whether this gets 'fixed', but it is technically >> not a bug (or, the only definitive error is that the comment doesn't >> match the implementation). >> >> -- Dan >> >> On Tue, Sep 23, 2014 at 5:45 PM, Thomas Miedema > > wrote: >> >> The implementation of nubBy in Data.List is as follows, where >> USE_REPORT_PRELUDE refers to [1]: >> >> #ifdef USE_REPORT_PRELUDE >> nubBy eq [] = [] >> nubBy eq (x:xs) = x : nubBy eq (filter (\ y -> not (eq >> x y)) xs) >> #else >> nubBy eq l = nubBy' l [] >> where >> nubBy' [] _ = [] >> nubBy' (y:ys) xs >> | elem_by eq y xs = nubBy' ys xs >> | otherwise = y : nubBy' ys (y:xs) >> >> -- Not exported: >> -- Note that we keep the call to `eq` with arguments in the >> -- same order as in the reference implementation >> -- 'xs' is the list of things we've seen so far, >> -- 'y' is the potential new element >> elem_by :: (a -> a -> Bool) -> a -> [a] -> Bool >> elem_by _ _ [] = False >> elem_by eq y (x:xs) = y `eq` x || elem_by eq y xs >> #endif >> >> That comment is actually not correct [2], and the report version and >> the base >> version don't have the same semantics when used on asymmetric >> relations: >> >> MyReportPrelude> nubBy (<) [1] >> [1] >> >> Data.List> nubBy (<) [1,2] >> [1,2] >> >> ## Proposal >> Make nubBy and nub obey the report semantics by swapping the >> arguments to >> `eq` in elem_by, and defining nub as nubBy (==). This is the 'still >> easy' >> variant from [3]. >> >> ## Motivation >> The Report's order is more sensible, since the parameters to the >> relation stay >> in the left-to-right order in which they occurred in the list. See >> [4,5] for >> user bug reports. >> >> Discussion period: 2 weeks >> Code review: https://phabricator.haskell.org/D238 >> >> [1] https://www.haskell.org/onlinereport/list.html#sect17.6 >> [2] https://ghc.haskell.org/trac/ghc/ticket/2528 >> [3] https://ghc.haskell.org/trac/ghc/ticket/7913#comment:3 >> [4] https://ghc.haskell.org/trac/ghc/ticket/3280 >> [5] https://ghc.haskell.org/trac/ghc/ticket/7913 >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://www.haskell.org/mailman/listinfo/libraries >> >> > > -- > Andreas Abel <>< Du bist der geliebte Mensch. > > Department of Computer Science and Engineering > Chalmers and Gothenburg University, Sweden > > andreas.abel at gu.se > http://www2.tcs.ifi.lmu.de/~abel/ > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Wed Oct 29 11:25:07 2014 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 29 Oct 2014 13:25:07 +0200 Subject: Discussion: adding displayException to Exception class In-Reply-To: <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: On Wed, Oct 29, 2014 at 1:18 PM, Simon Peyton Jones wrote: > If people want Show to generate something that can be copy/pasted into a > Haskell source file, that?s a legitimate position. But please let?s not > call it ?serialisation?! > > > To be clear: people in this thread expressed the copy/paste concept. In the previous thread, serialization via Show/Read combination was definitely advocated. To hopefully flesh out all of the different positions I've seen expressed so far: 1. Express a valid Haskell expression for copy/paste reasons. 2. Express a valid Haskell expression to make it easy to determine the type of the exception thrown (even though that's not always enough information). 3. Express something that can be consumed by Read for easy serialization. 4. Print something which is meaningful to a Haskell developer. 5. Print something which would be meaningful to an end user. I agree completely that (3) should be handled by Binary (or equivalent: ToJSON/FromJSON, cereal, Storable...). And it seems like (1) and (4) should overlap perfectly, with one little exception: there are some things (like a Handle, IO action or function) which could be printed but not copy-pasted. (2) would likely be handled better via Typeable, possibly with some extra plumbing for cases like extensible exceptions. This is a great time for everyone to jump in with the use cases they care about that I've missed... > So we have: > > 1. Serialisation (use Binary) > > 2. Copy-pasteable into Haskell source file, but not necessarily > human-readable (Show) > > 3. Human readable (Display) > > > > It?s clearly a library-design issue whether (2) and (3) are worth > separating. More classes, more code, but perhaps more expressiveness. > What does the core libraries committee think? Personally I don?t see (2) > as particularly important, but my opinion counts for little since I?m not a > library author. > > > > Simon > > > > *From:* Libraries [mailto:libraries-bounces at haskell.org] *On Behalf Of *Michael > Snoyman > *Sent:* 29 October 2014 11:02 > *To:* Simon Peyton Jones > *Cc:* libraries > *Subject:* Re: Discussion: adding displayException to Exception class > > > > > > > > On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones < > simonpj at microsoft.com> wrote: > > As I recently commented on this list[1], the Show typeclass is > overloaded with multiple meanings (serialization, debug info, and > user-friendly data display). The general consensus seems to be that the > official semantics for Show should be for serialization (as paired up with > Read). > > > > Really? My instinct is otherwise: *to use Show for human-readable > display, and Binary for serialisation*. Show/Read is a terribly > inefficient serialisation format; as soon as you want to do it for real you > end up with Binary anyway. And Show is already well established for > human-readable purposes ? that was one of its primary original purposes. > > > > Simon > > > > My weak vote in that thread went towards Show for human-readable display, > but there was some quite harsh objection to that position. In this thread > too you can see people wanting a direct encoding of types which can be > copy-pasted into a Haskell source file. Personally, I don't see much need > for that, and especially given the new ability to essentially auto-derive > Binary instances (via Generic), Show/Read serialization seems fairly > pointless. > > Nonetheless, making a proposal that doesn't enforce a changed semantics on > the Show typeclass seems like the path of least resistance. If others want > to jump back into the previous topic and try to hammer down the ideal usage > of the Show typeclass, I'm happy to participate in that discussion too. > > Michael > -------------- next part -------------- An HTML attachment was scrubbed... URL: From dominique.devriese at cs.kuleuven.be Wed Oct 29 11:43:13 2014 From: dominique.devriese at cs.kuleuven.be (Dominique Devriese) Date: Wed, 29 Oct 2014 12:43:13 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: 2014-10-29 12:25 GMT+01:00 Michael Snoyman : > [possible use cases for Show] > 1. Express a valid Haskell expression for copy/paste reasons. > 2. Express a valid Haskell expression to make it easy to determine the type > of the exception thrown (even though that's not always enough information). > 3. Express something that can be consumed by Read for easy serialization. > 4. Print something which is meaningful to a Haskell developer. > 5. Print something which would be meaningful to an end user. If we enter this discussion, I think we should keep in mind how some of these uses are encouraged by the infrastructure. Specifically: * the fact that GHCi uses Show for printing result values, counts (at least for me) as an implicit vote for use case (4) * the fact that deriving Show is directly supported by the compiler (contrary to Binary, for example) making it easier to use Show than more appropriate alternatives. If we think Show is the wrong solution for serialisation, then maybe the compiler should provide equivalent support for a more adequate solution, for example? Regards, Dominique From michael at snoyman.com Wed Oct 29 11:46:32 2014 From: michael at snoyman.com (Michael Snoyman) Date: Wed, 29 Oct 2014 13:46:32 +0200 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: On Wed, Oct 29, 2014 at 1:43 PM, Dominique Devriese < dominique.devriese at cs.kuleuven.be> wrote: > 2014-10-29 12:25 GMT+01:00 Michael Snoyman : > > [possible use cases for Show] > > 1. Express a valid Haskell expression for copy/paste reasons. > > 2. Express a valid Haskell expression to make it easy to determine the > type > > of the exception thrown (even though that's not always enough > information). > > 3. Express something that can be consumed by Read for easy serialization. > > 4. Print something which is meaningful to a Haskell developer. > > 5. Print something which would be meaningful to an end user. > > If we enter this discussion, I think we should keep in mind how some > of these uses are encouraged by the infrastructure. Specifically: > * the fact that GHCi uses Show for printing result values, counts (at > least for me) as an implicit vote for use case (4) > * the fact that deriving Show is directly supported by the compiler > (contrary to Binary, for example) making it easier to use Show than > more appropriate alternatives. If we think Show is the wrong solution > for serialisation, then maybe the compiler should provide equivalent > support for a more adequate solution, for example? > > Regards, > Dominique > Those are good points. For your first one: that's why my quasi-proposal stated that GHC's default exception handler should switch over to using the new pretty-printed exception method (since I'd like (5) to be the target in that case). Regarding your second point: Generic-based instances go a long way towards solving that problem, and- unless I'm mistaken- starting with GHC 7.10 it will be possible to do something like: data Foo = ... deriving (Generic, Binary, ToJSON, FromJSON) Michael -------------- next part -------------- An HTML attachment was scrubbed... URL: From simonpj at microsoft.com Wed Oct 29 12:37:45 2014 From: simonpj at microsoft.com (Simon Peyton Jones) Date: Wed, 29 Oct 2014 12:37:45 +0000 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: <618BE556AADD624C9C918AA5D5911BEF3F380A2E@DB3PRD3001MB020.064d.mgd.msft.net> | * the fact that deriving Show is directly supported by the compiler | (contrary to Binary, for example) making it easier to use Show than | more appropriate alternatives. If we think Show is the wrong solution | for serialisation, then maybe the compiler should provide equivalent | support for a more adequate solution, for example? yes, that's quite possible. From mgsloan at gmail.com Wed Oct 29 13:42:10 2014 From: mgsloan at gmail.com (Michael Sloan) Date: Wed, 29 Oct 2014 06:42:10 -0700 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: Message-ID: I strongly agree with this proposal. It's nice to encode in the API that these error messages are expected to be displayed to users of applications, and not just developers. A particularly blatant example of this going wrong is in System.IO.Error, where you get this delightful behavior: > fail "brain exploded" *** Exception: user error (brain exploded) The poor user is going to think that the program is accusing them of having an exploded brain. Similarly: Prelude> Just x <- return Nothing *** Exception: user error (Pattern match failure in do expression at :5:1-6) This is clearly a programming error, not a "user error". In order to encourage thought about application user consumption of error messages, I think a couple warnings ought to be added: 1) A warning when the definition of "displayException" is omitted. This would be a new GHC warning pragma, which could potentially re-use the syntax from MINIMAL, to make the warning more flexible. It would recommend that they write a custom implementation and consider how the error will look to application users (though, not at the cost of informativeness to developers). It could also warn about the pending removal of the Show superclass and default implementation of "displayException", if that was decided on (I think it should be!) 2) A warning for all uses of "show :: a -> String" when in a context where "Exception a" holds. This would also be a new variety of warning, potentially hardcoded in GHC, but ideally generalized. It's important to have this warning because users might still be using 'show' when 'displayException' is more appropriate. How to suppress such warnings when you really do want 'show'? A "showException = show" function would work for that. A warning when "Show a" is used when in a context where "Exception a" holds would catch additional cases. However, it would be much more spammy and unclear how to suppress it. I think the warning describe above is still worth it, though, even if it's just to catch situations where 'show' is being used on a nested exception value in order to implement the 'displayException' method (or the instance of Show that relies on). This would also ease the pain of removing Show as a superclass constraint. I imagine this removal would break more code than the removal of Eq / Show as superclasses of Num. Michael On Tue, Oct 28, 2014 at 4:43 PM, Michael Snoyman wrote: > I don't want to make a format proposal yet, just open up discussion on an > issue, and see how others feel about it. > > As I recently commented on this list[1], the Show typeclass is overloaded > with multiple meanings (serialization, debug info, and user-friendly data > display). The general consensus seems to be that the official semantics for > Show should be for serialization (as paired up with Read). > > However, there's at least one use case in base which explicitly uses Show > for non-serialization purposes: the Exception class. All instances of > Exception are required to have an instance of Show, but there's no way to > actually serialize exceptions generally[2]. So by construction and by > practice, the Show instance for Exception is used exclusively for the latter > two categories I mentioned (debug info and user-friendly data display). > > As a result of that, it's quite common[3] to define a Show instance for > exception types that is *not* serializable, but rather user friendly. This > however seems to contradict what is accepted as good practice in general. > > > I have a possible solution that I'd like to propose as a strawman: add a new > method to the Exception typeclass: > > displayException :: e -> String > displayException = show > > The name is up for debate, but I chose `display` since it seems to already > be used elsewhere for user-friendly output. Other possible choices are > showException or prettyException. The default implementation will reuse the > Show instance, so no user code will be broken by this[4]. > > In the short term, the only other change I'd recommend is that the default > exception handler use `displayException` instead of `show` for printing > uncaught exceptions. Longer term, after deprecation cycles, we could > consider removing the Show superclass from Exception. > > Again, this isn't a real proposal (yet), I'm more interested now in what > people think about such a change. > > Michael > > [1] http://www.haskell.org/pipermail/libraries/2014-October/023957.html > [2] Both due to how extensible exceptions work, and due to the lack of a > Read superclass. > [3] This discussion started when Chris Done and I were working with the tar > package, which defines custom renderings for FormatError. I've implemented > this same technique in some of my libraries, and I'm sure there are many > other examples on Hackage. > [4] Barring the standard issue of new identifiers clashing with identifiers > defined locally. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > From mgsloan at gmail.com Wed Oct 29 13:56:52 2014 From: mgsloan at gmail.com (Michael Sloan) Date: Wed, 29 Oct 2014 06:56:52 -0700 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: Agreed! I think there has been general consensus that when possible, Show should generate valid Haskell code. Suppose that you want to reproduce some bug where a specific set of functions are suspected. If there arguments are 'Show' instances, then you can output invocations of these functions to a file. This file can now be used as an executable, minimizable reproduction of the bug! Honestly, I think 'Read' isn't all that important except for things like parsing numbers, very small applications. and prototypes. In practical code, you either end up using a serialization like binary or aeson, or writing your own pretty printer / parser. I'd rather have the property that 'show' results in code than the property that "read . show === id" (but certainly this is a nice property to have!). Michael On Wed, Oct 29, 2014 at 4:25 AM, Michael Snoyman wrote: > > > On Wed, Oct 29, 2014 at 1:18 PM, Simon Peyton Jones > wrote: >> >> If people want Show to generate something that can be copy/pasted into a >> Haskell source file, that?s a legitimate position. But please let?s not >> call it ?serialisation?! >> >> > > To be clear: people in this thread expressed the copy/paste concept. In the > previous thread, serialization via Show/Read combination was definitely > advocated. To hopefully flesh out all of the different positions I've seen > expressed so far: > > 1. Express a valid Haskell expression for copy/paste reasons. > 2. Express a valid Haskell expression to make it easy to determine the type > of the exception thrown (even though that's not always enough information). > 3. Express something that can be consumed by Read for easy serialization. > 4. Print something which is meaningful to a Haskell developer. > 5. Print something which would be meaningful to an end user. > > I agree completely that (3) should be handled by Binary (or equivalent: > ToJSON/FromJSON, cereal, Storable...). And it seems like (1) and (4) should > overlap perfectly, with one little exception: there are some things (like a > Handle, IO action or function) which could be printed but not copy-pasted. > (2) would likely be handled better via Typeable, possibly with some extra > plumbing for cases like extensible exceptions. > > This is a great time for everyone to jump in with the use cases they care > about that I've missed... > >> >> So we have: >> >> 1. Serialisation (use Binary) >> >> 2. Copy-pasteable into Haskell source file, but not necessarily >> human-readable (Show) >> >> 3. Human readable (Display) >> >> >> >> It?s clearly a library-design issue whether (2) and (3) are worth >> separating. More classes, more code, but perhaps more expressiveness. >> What does the core libraries committee think? Personally I don?t see (2) as >> particularly important, but my opinion counts for little since I?m not a >> library author. >> >> >> >> Simon >> >> >> >> From: Libraries [mailto:libraries-bounces at haskell.org] On Behalf Of >> Michael Snoyman >> Sent: 29 October 2014 11:02 >> To: Simon Peyton Jones >> Cc: libraries >> Subject: Re: Discussion: adding displayException to Exception class >> >> >> >> >> >> >> >> On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones >> wrote: >> >> As I recently commented on this list[1], the Show typeclass is overloaded >> with multiple meanings (serialization, debug info, and user-friendly data >> display). The general consensus seems to be that the official semantics for >> Show should be for serialization (as paired up with Read). >> >> >> >> Really? My instinct is otherwise: to use Show for human-readable display, >> and Binary for serialisation. Show/Read is a terribly inefficient >> serialisation format; as soon as you want to do it for real you end up with >> Binary anyway. And Show is already well established for human-readable >> purposes ? that was one of its primary original purposes. >> >> >> >> Simon >> >> >> >> My weak vote in that thread went towards Show for human-readable display, >> but there was some quite harsh objection to that position. In this thread >> too you can see people wanting a direct encoding of types which can be >> copy-pasted into a Haskell source file. Personally, I don't see much need >> for that, and especially given the new ability to essentially auto-derive >> Binary instances (via Generic), Show/Read serialization seems fairly >> pointless. >> >> Nonetheless, making a proposal that doesn't enforce a changed semantics on >> the Show typeclass seems like the path of least resistance. If others want >> to jump back into the previous topic and try to hammer down the ideal usage >> of the Show typeclass, I'm happy to participate in that discussion too. >> >> Michael > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > From ekmett at gmail.com Wed Oct 29 15:09:57 2014 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 29 Oct 2014 11:09:57 -0400 Subject: [core libraries] Re: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: I could definitely see adding a separate displayException method to Exception. +1 there. Removing Show as a superclass however is something we'd have to check, its the kind of thing where it'd silently affect some code that was just accepting the exception and printing it in a manner that could be worked around by using a pair of constraints, just like the change breaking up Num that Ian put through a few years back. If that is something folks *really* want to do, we could probably get there. If we did then you'd probably want class Typeable a => Exception a where ... displayException :: a -> String default displayException :: Show a => a -> String displayException = show which would let most of the existing code around it work, and only break the code that takes an exception blindly and prints it. Adding displayException strikes me as easy, and zero-pain. Removing Show on the other hand is something I'm somewhat less sanguine about, but not either for or against. -Edward On Wed, Oct 29, 2014 at 9:56 AM, Michael Sloan wrote: > Agreed! > > I think there has been general consensus that when possible, Show > should generate valid Haskell code. Suppose that you want to > reproduce some bug where a specific set of functions are suspected. > If there arguments are 'Show' instances, then you can output > invocations of these functions to a file. This file can now be used > as an executable, minimizable reproduction of the bug! > > Honestly, I think 'Read' isn't all that important except for things > like parsing numbers, very small applications. and prototypes. In > practical code, you either end up using a serialization like binary or > aeson, or writing your own pretty printer / parser. I'd rather have > the property that 'show' results in code than the property that "read > . show === id" (but certainly this is a nice property to have!). > > Michael > > On Wed, Oct 29, 2014 at 4:25 AM, Michael Snoyman > wrote: > > > > > > On Wed, Oct 29, 2014 at 1:18 PM, Simon Peyton Jones < > simonpj at microsoft.com> > > wrote: > >> > >> If people want Show to generate something that can be copy/pasted into a > >> Haskell source file, that?s a legitimate position. But please let?s not > >> call it ?serialisation?! > >> > >> > > > > To be clear: people in this thread expressed the copy/paste concept. In > the > > previous thread, serialization via Show/Read combination was definitely > > advocated. To hopefully flesh out all of the different positions I've > seen > > expressed so far: > > > > 1. Express a valid Haskell expression for copy/paste reasons. > > 2. Express a valid Haskell expression to make it easy to determine the > type > > of the exception thrown (even though that's not always enough > information). > > 3. Express something that can be consumed by Read for easy serialization. > > 4. Print something which is meaningful to a Haskell developer. > > 5. Print something which would be meaningful to an end user. > > > > I agree completely that (3) should be handled by Binary (or equivalent: > > ToJSON/FromJSON, cereal, Storable...). And it seems like (1) and (4) > should > > overlap perfectly, with one little exception: there are some things > (like a > > Handle, IO action or function) which could be printed but not > copy-pasted. > > (2) would likely be handled better via Typeable, possibly with some extra > > plumbing for cases like extensible exceptions. > > > > This is a great time for everyone to jump in with the use cases they care > > about that I've missed... > > > >> > >> So we have: > >> > >> 1. Serialisation (use Binary) > >> > >> 2. Copy-pasteable into Haskell source file, but not necessarily > >> human-readable (Show) > >> > >> 3. Human readable (Display) > >> > >> > >> > >> It?s clearly a library-design issue whether (2) and (3) are worth > >> separating. More classes, more code, but perhaps more expressiveness. > >> What does the core libraries committee think? Personally I don?t see > (2) as > >> particularly important, but my opinion counts for little since I?m not a > >> library author. > >> > >> > >> > >> Simon > >> > >> > >> > >> From: Libraries [mailto:libraries-bounces at haskell.org] On Behalf Of > >> Michael Snoyman > >> Sent: 29 October 2014 11:02 > >> To: Simon Peyton Jones > >> Cc: libraries > >> Subject: Re: Discussion: adding displayException to Exception class > >> > >> > >> > >> > >> > >> > >> > >> On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones > >> wrote: > >> > >> As I recently commented on this list[1], the Show typeclass is > overloaded > >> with multiple meanings (serialization, debug info, and user-friendly > data > >> display). The general consensus seems to be that the official semantics > for > >> Show should be for serialization (as paired up with Read). > >> > >> > >> > >> Really? My instinct is otherwise: to use Show for human-readable > display, > >> and Binary for serialisation. Show/Read is a terribly inefficient > >> serialisation format; as soon as you want to do it for real you end up > with > >> Binary anyway. And Show is already well established for human-readable > >> purposes ? that was one of its primary original purposes. > >> > >> > >> > >> Simon > >> > >> > >> > >> My weak vote in that thread went towards Show for human-readable > display, > >> but there was some quite harsh objection to that position. In this > thread > >> too you can see people wanting a direct encoding of types which can be > >> copy-pasted into a Haskell source file. Personally, I don't see much > need > >> for that, and especially given the new ability to essentially > auto-derive > >> Binary instances (via Generic), Show/Read serialization seems fairly > >> pointless. > >> > >> Nonetheless, making a proposal that doesn't enforce a changed semantics > on > >> the Show typeclass seems like the path of least resistance. If others > want > >> to jump back into the previous topic and try to hammer down the ideal > usage > >> of the Show typeclass, I'm happy to participate in that discussion too. > >> > >> Michael > > > > > > > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://www.haskell.org/mailman/listinfo/libraries > > > > -- > You received this message because you are subscribed to the Google Groups > "haskell-core-libraries" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to haskell-core-libraries+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chrisdone at gmail.com Wed Oct 29 15:20:24 2014 From: chrisdone at gmail.com (Christopher Done) Date: Wed, 29 Oct 2014 16:20:24 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: I?m a bit late but I thought I?d chime in as the Show situation is delicate for me. Pretty much as you said, I?d categorize printing (of general Haskell values) by the audience: Users Programmers Programs Here?s an example of each: "The tar archive is corrupt (truncated)." :: String TruncatedArchive :: FormatError "\1" :: ByteString I would like to add that for the kind targeting programmers, it?s not that I would necessarily like to be able to copy/paste the printing of something into my source code. I use Show for debugging. Rather, I want to know what the value is. So I need the constructor and any fields in it. I think it?s essential for debugging, and I feel spoiled in Haskell that most types have a reasonable Show instance that shows the structure of a value for me. But often, cases like this, it?s just a human-readable string which, as a programmer, is very unhelpful to me. So we already have standard ways of doing each of these, of course: We have things like Doc for pretty printing for users. We have Show for printing the structure of a value. We have binary/cereal/aeson for serializing. The issue is that pretty printing is not very helpful for me. For example, working with the GHC API is particularly difficult because almost all types do not have a Show instance. This breaks my normal Haskell development workflow, which is that I?ll run a function and print out the values. For example, say I?m working with Core and I have an Expr type. I?m pattern matching on the AST constructor by constructor. I generate some core, and I want to see what constructor is used where. If I use the Outputable class to print the Core, all I get is a pretty printed concrete syntax. Pretty, but not useful to me. How can I get that information? So I end up defining a gshow :: Data => a -> Show function, just to see exactly the structure of the data I?m working with, which is what show normally gives me. I think the case of ?being able to copy/paste it as source code? is a little bit out of place given things like fromList [(1,'a')] for a Map Int Char and Handle {<1>} (or whatever it was for the Handle type). The Handle?s Show instance is, to my mind, a perfectly legitimate instance for telling you what this value is. It contains an fd and it prints it. It has no Read instance, there?s no pretense of being ?serializable? or ?copy/pastable?. I have the same issues with exceptions, as noted by Michael. I?d like to know as a programmer what the exception is, as a Haskell value. Separately a way of printing exceptions for users would be welcome too and in the case of web/UI apps it seems very useful. From thomasmiedema at gmail.com Wed Oct 29 15:23:37 2014 From: thomasmiedema at gmail.com (Thomas Miedema) Date: Wed, 29 Oct 2014 16:23:37 +0100 Subject: Proposal: remove versionTags from Data.Version In-Reply-To: References: Message-ID: This proposal is now accepted, with support from Duncan, Herbert and myself. No objections were raised. If all goes well, versionTags will be deprecated in GHC 7.10, and removed in GHC 7.12. Code review: https://phabricator.haskell.org/D395 Ticket: https://ghc.haskell.org/trac/ghc/ticket/2496 On Tue, Sep 23, 2014 at 11:57 PM, Thomas Miedema wrote: > Version in Data.Version from base is defined as: > > data Version = Version { versionBranch :: [Int], versionTags :: > [String] } > > instance Eq Version where > v1 == v2 = versionBranch v1 == versionBranch v2 > && sort (versionTags v1) == sort (versionTags v2) > -- tags may be in any order > > instance Ord Version where > v1 `compare` v2 = versionBranch v1 `compare` versionBranch v2 > > > ## Proposal > Remove the `versionTags` field from this type. > > > ## Motivation > * The Eq and Ord instances of Version don't agree whether two versions > with different versionTags are equal or not [1]: > > > a = Version [1] ["a"] > > b = Version [1] ["b"] > > compare a b > EQ > > a == b > False > > * The Package versioning policy does not include version tags [2]. > * Cabal no longer supports package version tags [3,4]. > > Discussion period: 2 weeks. > > Note: this is not a proposal to ignore trailing zeros when comparing > versions. Neither is this is a proposal to change the Eq instance for > Version to only consider the versionBranch field. This is a proposal to > remove versionTags altogether. > > [1] https://ghc.haskell.org/trac/ghc/ticket/2496 > [2] http://www.haskell.org/haskellwiki/Package_versioning_policy > [3] https://github.com/haskell/cabal/issues/890 > [4] > http://www.haskell.org/cabal/users-guide/developing-packages.html#package-names-and-versions > -------------- next part -------------- An HTML attachment was scrubbed... URL: From benno.fuenfstueck at gmail.com Wed Oct 29 18:14:54 2014 From: benno.fuenfstueck at gmail.com (=?UTF-8?B?QmVubm8gRsO8bmZzdMO8Y2s=?=) Date: Wed, 29 Oct 2014 19:14:54 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: I just like to add that I find it very useful to be able to just copy the output of show to ghci. As an example, I wrote an AI that used a game tree as state. When debugging, I can just print this tree after each turn using show and then paste it to ghci to simulate the game starting from the state at that turn. If Show was not valid Haskell code, I would have had to write a serializer a d deserializer first, which isn't so easy to do for a tree structure. -- Benno -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Wed Oct 29 19:08:12 2014 From: david.feuer at gmail.com (David Feuer) Date: Wed, 29 Oct 2014 15:08:12 -0400 Subject: Proposal: Make default impls for foldl1 and foldr1 lazier Message-ID: We currently have (in Data.Foldable) foldr1 :: (a -> a -> a) -> t a -> a foldr1 f xs = fromMaybe (error "foldr1: empty structure") (foldr mf Nothing xs) where mf x Nothing = Just x mf x (Just y) = Just (f x y) and something similar for foldl1. This is strict in the entire spine, unlike the list version, because it has to get all the way to the end of the list before it starts laying down Justs. I propose we change this to the obvious: foldr1 :: (a -> a -> a) -> t a -> a foldr1 f xs = fromMaybe (error "foldr1: empty structure") (foldr mf Nothing xs) where mf x r = Just $ case r of Nothing -> x Just y -> f x y Since GHC 7.10.1 is fast approaching, I doubt we have the usual two weeks to discuss this, so please speak up as soon as you can if you have concerns. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jeremy at n-heptane.com Wed Oct 29 20:19:05 2014 From: jeremy at n-heptane.com (Jeremy Shaw) Date: Wed, 29 Oct 2014 15:19:05 -0500 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: On Wed, Oct 29, 2014 at 10:20 AM, Christopher Done wrote: > Rather, I > want to know what the value is. So I need the constructor and any > fields in it. I think it?s essential for debugging, and I feel spoiled > in Haskell that most types have a reasonable Show instance that shows > the structure of a value for me. > I think the case of ?being able to copy/paste it as source code? is a > little bit out of place given things like fromList [(1,'a')] for a > Map Int Char and Handle {<1>} (or whatever it was for the Handle > type). The Handle?s Show instance is, to my mind, a perfectly > legitimate instance for telling you what this value is. It contains an > fd and it prints it. It has no Read instance, there?s no pretense > of being ?serializable? or ?copy/pastable?. It is definitely the case that not all useful values can be shown as valid Haskell code. But in the cases where they can -- I think it is useful even if you never actually copy & paste. If the value is shown as valid Haskell then you truly have all the information you could possibly need about that value. And you get it in a syntax that you are already familiar with -- so there is no need to learn another way of reading things. I'm curious about your, fromList [(1, 'a')], example. That seems exactly like a case where the Show instance is providing you with valid Haskell code to recreate the value aside from issue that fromList could be ambiguous. If I had to create some rules for Show it would probably involve: 1. if it is possible to write a Read instance, then the Show instance should create valid Haskell code 2. if a Read instance is not possible, then the Show instance should come as close to valid Haskell as possible while yielding the maximum amount of information available. It seems like both Map and Handle would meet those requires. Map has Read/Show instances and the String format is valid Haskell. For Handle, a Read instance is not possible, but it does give you as much information as possible. I believe 'deriving (Read, Show)' naturally meets requirement #1 as long as any Read/Show instances it depends on also meet requirement #1 ? - jeremy From chrisdone at gmail.com Wed Oct 29 22:07:54 2014 From: chrisdone at gmail.com (Christopher Done) Date: Wed, 29 Oct 2014 23:07:54 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: Well, I think fromList [(1, 'a')] is kind of unhelpful: 1. It almost never is a straight copy/paste, you will have to go and add M. to the fromList. 2. It doesn?t actually tell you what you?re looking at: (fromList [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')] ,fromList [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')] ,fromList [1,2,3,4,5] ,fromList [1,2,3,4,5]) What are you looking at? Answer: > import qualified Data.Map as M > import qualified Data.HashMap.Strict as HM > import qualified Data.Vector as V > import qualified Data.Vector as S > (M.fromList (zip [0..5] ['a'..]) ,HM.fromList (zip [0..5] ['a'..]) ,S.fromList [1..5] ,V.fromList [1..5]) It?s true that numbers (Int/Integer) get a free pass on this, but I consider those an exception. I?d prefer (if we?re restricting ourselves to strings) something like Map [(0,'a'),(1,'b'),(2,'c')] StrictHashMap [(0,'a'),(1,'b'),(2,'c')] Set [0,1,2,3,4,5]Vector [0,1,2,3,4,5] But this is not the status quo and I don?t see it changing soon. People are set on the ?looks like code? idea more than ?describe the data structure?. ------------------------------ Digression: While we?re on the subject, I?d like to be able to convert any Haskell value to a Presentation which IDEs and browsers can use to trivially expand data structures lazily, like this: ?> present (fromJust (fromList [0])) [1..5]Just (List "[Integer]" [("Integer", at 0?0),("[Integer]", at 0?1)]) ?> present (fromJust (fromList [0,0])) (T.pack "hi")Just (Char "Char" "'h'") ?> present (fromJust (fromList [0,1])) (T.pack "hi")Just (String "Text" [("Char", at 0?1?0),("Text", at 0?1?1)]) ?> present (fromJust (fromList [0])) "hello!"Just (String "String" [("Char", at 0?0),("String", at 0?1)]) ?> present (fromJust (fromList [0,0])) "hello!"Just (Char "Char" "'h'") ?> present (fromJust (fromList [0,1,0])) "hello!"Just (Char "Char" "'e'") Video of Emacs taking advantage of this output. And to be able to choose *how to present* the structure. E.g. if I wanted, I could present a Set like: {0 1 2 3 4 5} and a Map like: { 0 => 'a', 1 => 'b', 2 => 'c' } and, let?s say I add a Tree constructor to the Presentation type, i.e. a known ?tree-ish? structure, then I can render a Data.Tree like: {0 1 2 3} / \ {4 5 6} {7 8 9} ? ? Where the ? is an expansion thing to click. Because Presentation contains type information, you can hover your mouse or whatever to inspect the types of things. But making this work in the general sense has been hard: Show is not parseable, many data types in real projects are not instances of Data (and types like Text and Vector have bogus instances). I believe my only recourse will be using the GHC API to inspect data types or template-haskell?s reify in an effort to cross module encapsulation. Now that Typeable is not user-definable, one cannot use the derive package, either. I think the :sprint/:print of GHCi is sort of there, but using it would be more hacky ? it would be better to hook into whatever API is used to produce that feature in GHC and spit out a Presentation. In general, it seems the current Haskell state of affairs makes it tricky to just print a value and expand it incrementally in the same way that you can in Common Lisp or JavaScript. ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From mail at nh2.me Thu Oct 30 01:22:23 2014 From: mail at nh2.me (=?windows-1252?Q?Niklas_Hamb=FCchen?=) Date: Thu, 30 Oct 2014 02:22:23 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: <545192CF.4020006@nh2.me> > 1. Serialisation (use Binary) > 2. Copy-pasteable into Haskell source file, but not necessarily > human-readable (Show) > 3. Human readable (Display) I agree a lot to this. While for Simon 2 doesn't seem to be useful, Show representing the Haskell value and its structure as much as possible is super useful when debugging business logic code, especially when it was written by other people years ago. It's rarely done, but when you actually do use ghci with break points, Show is a very useful (and necessary) tool to see what's in your values, and you wish every type had a Show instance - even better if it's a derived one. IMO, using Show for pretty printing defeats a lot of the above purpose, and thus I welcome any effort to separate Show and Display things (so +1). Yes, sometimes the Show instances aren't as nice as we would like them to be (e.g. fromList for Sets as Chris mentioned), but despite these unhappy cases, the debugging/programmer oriented nature of Show seems fundamental to me. There seems to be full consensus that Show (and any String based functionality) isn't a good idea for "serialisation as part of the program functionality". We just have to be careful to distinguish this from "serialisation for the programmer/debugging", since when people say just "serialisation" they can mean either. Regarding Jeremy's proposed rules for Read/Show, I would put them in different order: 1. the Show instance should always come as close to valid Haskell as possible 2. if it is possible to write a Read instance, write (best derive) one, otherwise don't (e.g. if your thing contains IORefs) From ekmett at gmail.com Thu Oct 30 01:30:14 2014 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 29 Oct 2014 21:30:14 -0400 Subject: [core libraries] Re: Discussion: adding displayException to Exception class In-Reply-To: <545192CF.4020006@nh2.me> References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> <545192CF.4020006@nh2.me> Message-ID: My experience is that whenever someone writes a "helpful" Show instance it winds up anything but. Why? What happens when you print a list of them, or they occur deeper in a larger structure? Invariably I wind up with things like a bag of your exceptions in an async exception wrapper or someone's position type in my data structure -- I first noticed this when I was working with parsec. I'd stick source positions in my data types, but Parsec was helpful: instance Show SourcePos where show (SourcePos name line column) | null name = showLineColumn | otherwise = "\"" ++ name ++ "\" " ++ showLineColumn where showLineColumn = "(line " ++ show line ++ ", column " ++ show column ++ ")" .. and with that now users can't made hide nor hair out of syntax tree terms, etc. "Helpful" Show instances are not compositional. -Edward On Wed, Oct 29, 2014 at 9:22 PM, Niklas Hamb?chen wrote: > > 1. Serialisation (use Binary) > > 2. Copy-pasteable into Haskell source file, but not necessarily > > human-readable (Show) > > 3. Human readable (Display) > > I agree a lot to this. > > While for Simon 2 doesn't seem to be useful, Show representing the > Haskell value and its structure as much as possible is super useful when > debugging business logic code, especially when it was written by other > people years ago. > > It's rarely done, but when you actually do use ghci with break points, > Show is a very useful (and necessary) tool to see what's in your values, > and you wish every type had a Show instance - even better if it's a > derived one. > > IMO, using Show for pretty printing defeats a lot of the above purpose, > and thus I welcome any effort to separate Show and Display things (so +1). > > Yes, sometimes the Show instances aren't as nice as we would like them > to be (e.g. fromList for Sets as Chris mentioned), but despite these > unhappy cases, the debugging/programmer oriented nature of Show seems > fundamental to me. > > There seems to be full consensus that Show (and any String based > functionality) isn't a good idea for "serialisation as part of the > program functionality". We just have to be careful to distinguish this > from "serialisation for the programmer/debugging", since when people say > just "serialisation" they can mean either. > > Regarding Jeremy's proposed rules for Read/Show, I would put them in > different order: > > 1. the Show instance should always come as close to valid Haskell > as possible > 2. if it is possible to write a Read instance, write (best derive) > one, otherwise don't (e.g. if your thing contains IORefs) > > -- > You received this message because you are subscribed to the Google Groups > "haskell-core-libraries" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to haskell-core-libraries+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From haskell at ibotty.net Thu Oct 30 10:00:51 2014 From: haskell at ibotty.net (Tobias Florek) Date: Thu, 30 Oct 2014 11:00:51 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: <20141030100051.22741.77021@x201.Speedport_W723_V_Typ_A_1_01_009> Quoting Christopher Done (2014-10-29 23:07:54) > Well, I think fromList [(1, 'a')] is kind of unhelpful: > > 1. It almost never is a straight copy/paste, you will have to go and add M. to > the fromList. Chris Done is hinting at a shortcoming to the usage of `Show` in the sense of Jeremy Shaw's ShowExpr: It does not support qualified imports at all. It might be nice to append a `My.Module` to each function in `show`'s output whenever a module is meant to be imported qualified. There might be some heuristics on when that's the case (hiding parts of `Prelude`), but that's certainly something only the compiler (or TH) can do. Cheers, tobias florek From chrisdone at gmail.com Thu Oct 30 10:20:00 2014 From: chrisdone at gmail.com (Christopher Done) Date: Thu, 30 Oct 2014 11:20:00 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: <20141030100051.22741.77021@x201.Speedport_W723_V_Typ_A_1_01_009> References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> <20141030100051.22741.77021@x201.Speedport_W723_V_Typ_A_1_01_009> Message-ID: On 30 October 2014 11:00, Tobias Florek haskell at ibotty.net wrote: Quoting Christopher Done (2014-10-29 23:07:54) Well, I think fromList [(1, ?a?)] is kind of unhelpful: 1. It almost never is a straight copy/paste, you will have to go and add M. to the fromList. Chris Done is hinting at a shortcoming to the usage of Show in the sense of Jeremy Shaw?s ShowExpr: It does not support qualified imports at all. It might be nice to append a My.Module to each function in show?s output whenever a module is meant to be imported qualified. There might be some heuristics on when that?s the case (hiding parts of Prelude), but that?s certainly something only the compiler (or TH) can do. Technically Data.Typeable has this information: > tyConModule (typeRepTyCon (typeOf (S.fromList [()])))"Data.Set.Base" > tyConName (typeRepTyCon (typeOf (S.fromList [()])))"Set" > tyConPackage (typeRepTyCon (typeOf (S.fromList [()])))"containers-0.5.5.1" Data.Generics.Text can give a more structured output (though it doesn?t), but then there lies the issue: > gshow TruncatedArchive :25:1: No instance for (Data FormatError) arising from a use of ?gshow? In the expression: gshow TruncatedArchive In an equation for ?it?: it = gshow TruncatedArchive Hardly any data types are actually instances of Data. And the ones that are can often be bogus, even ?standard? ones like Data.Vector and Data.Text: > gshow (V.fromList [1]) "(*** Exception: toConstr > gshow (T.pack "x") "(*** Exception: Data.Text.Text.toConstr So while Data.Data could be a perfect solution for printing, at the moment it can?t be relied upon to exist. ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From abela at chalmers.se Thu Oct 30 15:55:52 2014 From: abela at chalmers.se (Andreas Abel) Date: Thu, 30 Oct 2014 16:55:52 +0100 Subject: Proposal: Make default impls for foldl1 and foldr1 lazier In-Reply-To: References: Message-ID: <54525F88.7090302@chalmers.se> +1. Or, for the friends of point-free programming, foldr f = fromMaybe (error "foldr1: empty structure") . foldr (\ x -> Just . maybe x (f x)) Nothing On 29.10.2014 20:08, David Feuer wrote: > We currently have (in Data.Foldable) > > foldr1 :: (a -> a -> a) -> t a -> a > foldr1 f xs = fromMaybe (error "foldr1: empty structure") > (foldr mf Nothing xs) > where > mf x Nothing = Just x > mf x (Just y) = Just (f x y) > > and something similar for foldl1. This is strict in the entire spine, > unlike the list version, because it has to get all the way to the end of > the list before it starts laying down Justs. I propose we change this to > the obvious: > > foldr1 :: (a -> a -> a) -> t a -> a > foldr1 f xs = fromMaybe (error "foldr1: empty structure") > (foldr mf Nothing xs) > where > mf x r = Just $ case r of > Nothing -> x > Just y -> f x y > > Since GHC 7.10.1 is fast approaching, I doubt we have the usual two > weeks to discuss this, so please speak up as soon as you can if you have > concerns. > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From abela at chalmers.se Thu Oct 30 16:20:44 2014 From: abela at chalmers.se (Andreas Abel) Date: Thu, 30 Oct 2014 17:20:44 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: <5452655C.7050103@chalmers.se> As you notice, the show functions for collections are implemented wrongly, they should print Fully.Qualified.Module.fromList [(key,value),...] High time to repent now and not sin again. Positive example: https://hackage.haskell.org/package/Agda-2.4.0/docs/src/Agda-Utils-BiMap.html#BiMap On 29.10.2014 23:07, Christopher Done wrote: > Well, I think |fromList [(1, 'a')]| is kind of unhelpful: > > 1. It almost never is a straight copy/paste, you will have to go and > add M. to the fromList. > 2. It doesn?t actually tell you what you?re looking at: > > |(fromList [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')] > ,fromList [(0,'a'),(1,'b'),(2,'c'),(3,'d'),(4,'e'),(5,'f')] > ,fromList [1,2,3,4,5] > ,fromList [1,2,3,4,5]) > | > > What are you looking at? > > Answer: > > |>import qualified Data.Mapas M >>import qualified Data.HashMap.Strictas HM >>import qualified Data.Vectoras V >>import qualified Data.Vectoras S >> (M.fromList (zip [0..5] ['a'..]) > ,HM.fromList (zip [0..5] ['a'..]) > ,S.fromList [1..5] > ,V.fromList [1..5]) > | > > It?s true that numbers (|Int|/|Integer|) get a free pass on this, but > I consider those an exception. I?d prefer (if we?re restricting > ourselves to strings) something like > > |Map [(0,'a'),(1,'b'),(2,'c')] > StrictHashMap [(0,'a'),(1,'b'),(2,'c')] > Set [0,1,2,3,4,5] > Vector [0,1,2,3,4,5] > | > > But this is not the status quo and I don?t see it changing > soon. People are set on the ?looks like code? idea more than ?describe > the data structure?. > > ------------------------------------------------------------------------ > > Digression: > > While we?re on the subject, I?d like to be able to convert any Haskell > value to a > Presentation > > which > IDEs and browsers can use to trivially expand data structures lazily, > like this: > > |?> present (fromJust (fromList [0])) [1..5] > Just (List "[Integer]" [("Integer", at 0?0),("[Integer]", at 0?1)]) > ?> present (fromJust (fromList [0,0])) (T.pack"hi") > Just (Char "Char" "'h'") > ?> present (fromJust (fromList [0,1])) (T.pack"hi") > Just (String "Text" [("Char", at 0?1?0),("Text", at 0?1?1)]) > ?> present (fromJust (fromList [0]))"hello!" > Just (String "String" [("Char", at 0?0),("String", at 0?1)]) > ?> present (fromJust (fromList [0,0]))"hello!" > Just (Char "Char" "'h'") > ?> present (fromJust (fromList [0,1,0]))"hello!" > Just (Char "Char" "'e'") > | > > Video of Emacs taking advantage of this output. > > > And to be able to choose /how to present/ the structure. E.g. if I > wanted, I could present a |Set| like: > > |{0 1 2 3 4 5} > | > > and a |Map| like: > > |{0 => 'a',1 => 'b',2 => 'c' } > | > > and, let?s say I add a |Tree| constructor to the |Presentation| type, > i.e. a known ?tree-ish? structure, then I can render a |Data.Tree| like: > > | {0 1 2 3} > / \ > {4 5 6} {7 8 9} > ? ? > | > > Where the |?| is an expansion thing to click. Because |Presentation| > contains type information, you can hover your mouse or whatever to > inspect the types of things. > > But making this work in the general sense has been hard: Show is not > parseable, many data types in real projects are not instances of Data > (and types like Text and Vector have bogus instances). I believe my > only recourse will be using the GHC API to inspect data types or > template-haskell?s |reify| in an effort to cross module > encapsulation. Now that Typeable is not user-definable, one cannot use > the derive package, > either. I think the |:sprint|/|:print| of GHCi is sort of there, but > using it would be more hacky ? it would be better to hook into > whatever API is used to produce that feature in GHC and spit out a > |Presentation|. > > In general, it seems the current Haskell state of affairs makes it > tricky to just print a value and expand it incrementally in the same > way that you can in Common Lisp or JavaScript. > > ? > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From abela at chalmers.se Thu Oct 30 16:24:58 2014 From: abela at chalmers.se (Andreas Abel) Date: Thu, 30 Oct 2014 17:24:58 +0100 Subject: Discussion: adding displayException to Exception class In-Reply-To: <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> References: <618BE556AADD624C9C918AA5D5911BEF3F37F884@DB3PRD3001MB020.064d.mgd.msft.net> <618BE556AADD624C9C918AA5D5911BEF3F38090B@DB3PRD3001MB020.064d.mgd.msft.net> Message-ID: <5452665A.80702@chalmers.se> On 29.10.2014 12:18, Simon Peyton Jones wrote: > 1.Serialisation (use Binary) > > 2.Copy-pasteable into Haskell source file, but not necessarily > human-readable (Show) > > 3.Human readable (Display) +1. These should all be separate, and we want a standard class for 3. "Display" seems to be a good name. > It?s clearly a library-design issue whether (2) and (3) are worth > separating. More classes, more code, but perhaps more expressiveness. > What does the core libraries committee think? Personally I don?t see > (2) as particularly important, but my opinion counts for little since > I?m not a library author. > > Simon > > *From:*Libraries [mailto:libraries-bounces at haskell.org] *On Behalf Of > *Michael Snoyman > *Sent:* 29 October 2014 11:02 > *To:* Simon Peyton Jones > *Cc:* libraries > *Subject:* Re: Discussion: adding displayException to Exception class > > On Wed, Oct 29, 2014 at 10:45 AM, Simon Peyton Jones > > wrote: > > As I recently commented on this list[1], the Show typeclass is > overloaded with multiple meanings (serialization, debug info, and > user-friendly data display). The general consensus seems to be that > the official semantics for Show should be for serialization (as > paired up with Read). > > Really? My instinct is otherwise: *to use Show for human-readable > display, and Binary for serialisation*. Show/Read is a terribly > inefficient serialisation format; as soon as you want to do it for > real you end up with Binary anyway. And Show is already well > established for human-readable purposes ? that was one of its > primary original purposes. > > Simon > > My weak vote in that thread went towards Show for human-readable > display, but there was some quite harsh objection to that position. In > this thread too you can see people wanting a direct encoding of types > which can be copy-pasted into a Haskell source file. Personally, I don't > see much need for that, and especially given the new ability to > essentially auto-derive Binary instances (via Generic), Show/Read > serialization seems fairly pointless. > > Nonetheless, making a proposal that doesn't enforce a changed semantics > on the Show typeclass seems like the path of least resistance. If others > want to jump back into the previous topic and try to hammer down the > ideal usage of the Show typeclass, I'm happy to participate in that > discussion too. > > Michael > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > -- Andreas Abel <>< Du bist der geliebte Mensch. Department of Computer Science and Engineering Chalmers and Gothenburg University, Sweden andreas.abel at gu.se http://www2.tcs.ifi.lmu.de/~abel/ From david.feuer at gmail.com Thu Oct 30 16:46:32 2014 From: david.feuer at gmail.com (David Feuer) Date: Thu, 30 Oct 2014 12:46:32 -0400 Subject: Proposal: Add Alternative adapter to Data.Monoid Message-ID: I found myself needing this type in my current overhaul of Data.Foldable, but it seems to be generally useful: newtype Alt f a = Alt { getAlt :: f a } deriving (Eq,Ord,Show,Read,Typeable,Data,Generic,Num,Real, Floating, Fractional, RealFrac, RealFloat, Integral, Enum, Bounded,Ix,Functor,Foldable,Traversable,Applicative, Alternative,Monad,MonadPlus,MonadFix, IsString, IsList) -- The laundry list of derived instances is as recommended by Edward Kmett, who would probably want more added if someone can think of more. Some of them would, of course, need to be derived in other modules. The key instance is this: instance Alternative t => Monoid (Alt t a) where mempty = Alt empty (Alt m) `mappend` (Alt n) = Alt (m <|> n) -------------- next part -------------- An HTML attachment was scrubbed... URL: From jwlato at gmail.com Thu Oct 30 16:52:41 2014 From: jwlato at gmail.com (John Lato) Date: Thu, 30 Oct 2014 09:52:41 -0700 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: References: Message-ID: +1, I think I've defined one-off, specialized versions of this a dozen times. On Thu, Oct 30, 2014 at 9:46 AM, David Feuer wrote: > I found myself needing this type in my current overhaul of Data.Foldable, > but it seems to be generally useful: > > newtype Alt f a = Alt { getAlt :: f a } deriving > (Eq,Ord,Show,Read,Typeable,Data,Generic,Num,Real, > Floating, Fractional, RealFrac, RealFloat, Integral, Enum, > Bounded,Ix,Functor,Foldable,Traversable,Applicative, > Alternative,Monad,MonadPlus,MonadFix, IsString, IsList) > -- The laundry list of derived instances is as recommended by Edward > Kmett, who would probably want more added if someone can think of more. > Some of them would, of course, need to be derived in other modules. The key > instance is this: > > instance Alternative t => Monoid (Alt t a) where > mempty = Alt empty > (Alt m) `mappend` (Alt n) = Alt (m <|> n) > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Thu Oct 30 16:53:39 2014 From: ekmett at gmail.com (Edward Kmett) Date: Thu, 30 Oct 2014 12:53:39 -0400 Subject: [core libraries] Proposal: Make default impls for foldl1 and foldr1 lazier In-Reply-To: References: Message-ID: +1 from me. On Wed, Oct 29, 2014 at 3:08 PM, David Feuer wrote: > We currently have (in Data.Foldable) > > foldr1 :: (a -> a -> a) -> t a -> a > foldr1 f xs = fromMaybe (error "foldr1: empty structure") > (foldr mf Nothing xs) > where > mf x Nothing = Just x > mf x (Just y) = Just (f x y) > > and something similar for foldl1. This is strict in the entire spine, > unlike the list version, because it has to get all the way to the end of > the list before it starts laying down Justs. I propose we change this to > the obvious: > > foldr1 :: (a -> a -> a) -> t a -> a > foldr1 f xs = fromMaybe (error "foldr1: empty structure") > (foldr mf Nothing xs) > where > mf x r = Just $ case r of > Nothing -> x > Just y -> f x y > > Since GHC 7.10.1 is fast approaching, I doubt we have the usual two weeks > to discuss this, so please speak up as soon as you can if you have concerns. > > -- > You received this message because you are subscribed to the Google Groups > "haskell-core-libraries" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to haskell-core-libraries+unsubscribe at googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Thu Oct 30 16:55:56 2014 From: ekmett at gmail.com (Edward Kmett) Date: Thu, 30 Oct 2014 12:55:56 -0400 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: References: Message-ID: +1 from me. I'll happily delete my versions in `reducers` and `monoids`. On Thu, Oct 30, 2014 at 12:46 PM, David Feuer wrote: > I found myself needing this type in my current overhaul of Data.Foldable, > but it seems to be generally useful: > > newtype Alt f a = Alt { getAlt :: f a } deriving > (Eq,Ord,Show,Read,Typeable,Data,Generic,Num,Real, > Floating, Fractional, RealFrac, RealFloat, Integral, Enum, > Bounded,Ix,Functor,Foldable,Traversable,Applicative, > Alternative,Monad,MonadPlus,MonadFix, IsString, IsList) > -- The laundry list of derived instances is as recommended by Edward > Kmett, who would probably want more added if someone can think of more. > Some of them would, of course, need to be derived in other modules. The key > instance is this: > > instance Alternative t => Monoid (Alt t a) where > mempty = Alt empty > (Alt m) `mappend` (Alt n) = Alt (m <|> n) > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ollie at ocharles.org.uk Thu Oct 30 17:54:16 2014 From: ollie at ocharles.org.uk (Oliver Charles) Date: Thu, 30 Oct 2014 17:54:16 +0000 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: References: Message-ID: <87d299v3xz.fsf@fynder-widget.localhost> David Feuer writes: > I found myself needing this type in my current overhaul of Data.Foldable, > but it seems to be generally useful: +1, I can see myself wanting to reach for this. -- ocharles From chowells79 at gmail.com Fri Oct 31 16:35:54 2014 From: chowells79 at gmail.com (Carl Howells) Date: Fri, 31 Oct 2014 09:35:54 -0700 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: <87d299v3xz.fsf@fynder-widget.localhost> References: <87d299v3xz.fsf@fynder-widget.localhost> Message-ID: Oh right. This is what I joined this list to propose in the first place, then forgot about. Uh, do I get a vote? If I have one, I'm obviously +1 on the idea. On Thu, Oct 30, 2014 at 10:54 AM, Oliver Charles wrote: > David Feuer writes: > >> I found myself needing this type in my current overhaul of Data.Foldable, >> but it seems to be generally useful: > > +1, I can see myself wanting to reach for this. > > -- ocharles > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://www.haskell.org/mailman/listinfo/libraries From ekmett at gmail.com Fri Oct 31 16:47:20 2014 From: ekmett at gmail.com (Edward Kmett) Date: Fri, 31 Oct 2014 12:47:20 -0400 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: References: <87d299v3xz.fsf@fynder-widget.localhost> Message-ID: The one change I'd offer is this: instance Alternative f => Monoid (Alt f a) where mempty = Alt empty * mappend = coerce ((<|>) :: f a -> f a -> f a)* That way it doesn't eta-expand (<|>). -Edward On Fri, Oct 31, 2014 at 12:35 PM, Carl Howells wrote: > Oh right. This is what I joined this list to propose in the first > place, then forgot about. Uh, do I get a vote? If I have one, I'm > obviously +1 on the idea. > > On Thu, Oct 30, 2014 at 10:54 AM, Oliver Charles > wrote: > > David Feuer writes: > > > >> I found myself needing this type in my current overhaul of > Data.Foldable, > >> but it seems to be generally useful: > > > > +1, I can see myself wanting to reach for this. > > > > -- ocharles > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://www.haskell.org/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Fri Oct 31 16:49:06 2014 From: david.feuer at gmail.com (David Feuer) Date: Fri, 31 Oct 2014 12:49:06 -0400 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: References: <87d299v3xz.fsf@fynder-widget.localhost> Message-ID: And one more change: this can't go in Data.Monoid; it needs to go in Control.Applicative. I can't imagine anyone will care. On Oct 31, 2014 12:47 PM, "Edward Kmett" wrote: > The one change I'd offer is this: > > instance Alternative f => Monoid (Alt f a) where > mempty = Alt empty > * mappend = coerce ((<|>) :: f a -> f a -> f a)* > > That way it doesn't eta-expand (<|>). > > -Edward > > > On Fri, Oct 31, 2014 at 12:35 PM, Carl Howells > wrote: > >> Oh right. This is what I joined this list to propose in the first >> place, then forgot about. Uh, do I get a vote? If I have one, I'm >> obviously +1 on the idea. >> >> On Thu, Oct 30, 2014 at 10:54 AM, Oliver Charles >> wrote: >> > David Feuer writes: >> > >> >> I found myself needing this type in my current overhaul of >> Data.Foldable, >> >> but it seems to be generally useful: >> > >> > +1, I can see myself wanting to reach for this. >> > >> > -- ocharles >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://www.haskell.org/mailman/listinfo/libraries >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Fri Oct 31 16:50:34 2014 From: ekmett at gmail.com (Edward Kmett) Date: Fri, 31 Oct 2014 12:50:34 -0400 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: References: <87d299v3xz.fsf@fynder-widget.localhost> Message-ID: Actually that feels like a very wrong place for it. It may wind up having to go there, but I do care. =P -Edward On Fri, Oct 31, 2014 at 12:49 PM, David Feuer wrote: > And one more change: this can't go in Data.Monoid; it needs to go in > Control.Applicative. I can't imagine anyone will care. > On Oct 31, 2014 12:47 PM, "Edward Kmett" wrote: > >> The one change I'd offer is this: >> >> instance Alternative f => Monoid (Alt f a) where >> mempty = Alt empty >> * mappend = coerce ((<|>) :: f a -> f a -> f a)* >> >> That way it doesn't eta-expand (<|>). >> >> -Edward >> >> >> On Fri, Oct 31, 2014 at 12:35 PM, Carl Howells >> wrote: >> >>> Oh right. This is what I joined this list to propose in the first >>> place, then forgot about. Uh, do I get a vote? If I have one, I'm >>> obviously +1 on the idea. >>> >>> On Thu, Oct 30, 2014 at 10:54 AM, Oliver Charles >>> wrote: >>> > David Feuer writes: >>> > >>> >> I found myself needing this type in my current overhaul of >>> Data.Foldable, >>> >> but it seems to be generally useful: >>> > >>> > +1, I can see myself wanting to reach for this. >>> > >>> > -- ocharles >>> > _______________________________________________ >>> > Libraries mailing list >>> > Libraries at haskell.org >>> > http://www.haskell.org/mailman/listinfo/libraries >>> >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Fri Oct 31 17:30:04 2014 From: david.feuer at gmail.com (David Feuer) Date: Fri, 31 Oct 2014 13:30:04 -0400 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: References: <87d299v3xz.fsf@fynder-widget.localhost> Message-ID: We might be able to put it in Data.Monoid. I though I had some kind of weird problem with that, but I don't remember. On Fri, Oct 31, 2014 at 12:50 PM, Edward Kmett wrote: > Actually that feels like a very wrong place for it. > > It may wind up having to go there, but I do care. =P > > -Edward > > > > > On Fri, Oct 31, 2014 at 12:49 PM, David Feuer > wrote: > >> And one more change: this can't go in Data.Monoid; it needs to go in >> Control.Applicative. I can't imagine anyone will care. >> On Oct 31, 2014 12:47 PM, "Edward Kmett" wrote: >> >>> The one change I'd offer is this: >>> >>> instance Alternative f => Monoid (Alt f a) where >>> mempty = Alt empty >>> * mappend = coerce ((<|>) :: f a -> f a -> f a)* >>> >>> That way it doesn't eta-expand (<|>). >>> >>> -Edward >>> >>> >>> On Fri, Oct 31, 2014 at 12:35 PM, Carl Howells >>> wrote: >>> >>>> Oh right. This is what I joined this list to propose in the first >>>> place, then forgot about. Uh, do I get a vote? If I have one, I'm >>>> obviously +1 on the idea. >>>> >>>> On Thu, Oct 30, 2014 at 10:54 AM, Oliver Charles >>>> wrote: >>>> > David Feuer writes: >>>> > >>>> >> I found myself needing this type in my current overhaul of >>>> Data.Foldable, >>>> >> but it seems to be generally useful: >>>> > >>>> > +1, I can see myself wanting to reach for this. >>>> > >>>> > -- ocharles >>>> > _______________________________________________ >>>> > Libraries mailing list >>>> > Libraries at haskell.org >>>> > http://www.haskell.org/mailman/listinfo/libraries >>>> >>> >>> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mblazevic at stilo.com Fri Oct 31 21:02:44 2014 From: mblazevic at stilo.com (=?UTF-8?B?TWFyaW8gQmxhxb5ldmnEhw==?=) Date: Fri, 31 Oct 2014 17:02:44 -0400 Subject: Proposal: Add Alternative adapter to Data.Monoid In-Reply-To: References: Message-ID: <5453F8F4.8020302@stilo.com> > instance Alternative t => Monoid (Alt t a) where > mempty = Alt empty > (Alt m) `mappend` (Alt n) = Alt (m <|> n) +1