From ndospark320 at naver.com Wed May 2 12:44:44 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Wed, 02 May 2018 21:44:44 +0900 Subject: =?utf-8?B?SW5zdGFuY2Ugb2YgYFNlbWlncm91cCAoRWl0aGVyIGEgYilgIG5lZWRzIHRvIGJlIGV2ZQ==?= =?utf-8?B?bnR1YWxseSBjaGFuZ2VkLg==?= Message-ID: <4c6c2e4f6a6b6b56e0f1872f312caa7@cweb03.nm.nhnsystem.com> Now since `base` package version `4.11.0.0`, `Monoid` is a subclass of `Semigroup`. And that made `Monoid (Either a b)` instance impossible to exist. Current (`4.11.0.1`) instance of `Semigroup (Either a b)` (excluding `stimes`: {{{#!hs -- | @since 4.9.0.0 instance Semigroup (Either a b) where Left _ <> b = b a <> _ = a }}} No value of `Either a b` can be `mempty`. This must be eventually changed to: {{{#!hs instance Semigroup a => Semigroup (Either a b) where Left a <> Left b = Left (a <> b) Left _ <> b = b a <> _ = a }}} The former behavior can be made with `Either (Last a) b`. This makes `Monoid (Either a b)` possible: {{{#!hs instance Monoid a => Monoid (Either a b) where mempty = Left mempty }}} Also `Alternative (Either e)`: {{{#!hs instance Monoid e => Alternative (Either e) where empty = mempty (<|>) = (<>) }}} -------------- next part -------------- An HTML attachment was scrubbed... URL: From ndospark320 at naver.com Wed May 2 14:31:55 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Wed, 02 May 2018 23:31:55 +0900 Subject: =?utf-8?B?TW9ub2lkIG92ZXIgWE9SIG9yIFhOT1IsIGFuZCBNb25vaWQgbGlmdGVkIGJ5IEFwcGxpYw==?= =?utf-8?B?YXRpdmUu?= Message-ID: <4664b84458b828b68b9b5e92fde9b3@cweb09.nm.nhnsystem.com> Logical XOR is associative, also is XNOR. And they both have an identity element. Hence: newtype Even = Even {getEven :: Bool} newtype Odd = Odd {getOdd :: Bool} instance Semigroup Even where (<>) = (==) -- (==) over Bool == Logical XNOR instance Semigroup Odd where (<>) = (/=) -- (/=) over Bool == Logical XOR instance Monoid Even where mempty = True instance Monoid Odd where mempty = False So foldMap would determine the parity of the number of Trues. Also, Monoid lifted by Applicative is also Monoid. This might be useful: newtype AMonoid f a = AMonoid {getAMonoid :: f a} instance (Applicative f, Semigroup a) => Semigroup (AMonoid f a) where (<>) = liftA2 (<>) instance (Applicative f, Monoid a) => Monoid (AMonoid f a) where mempty = pure mempty -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrew.thaddeus at gmail.com Wed May 2 14:34:26 2018 From: andrew.thaddeus at gmail.com (Andrew Martin) Date: Wed, 2 May 2018 10:34:26 -0400 Subject: Monoid over XOR or XNOR, and Monoid lifted by Applicative. In-Reply-To: <4664b84458b828b68b9b5e92fde9b3@cweb09.nm.nhnsystem.com> References: <4664b84458b828b68b9b5e92fde9b3@cweb09.nm.nhnsystem.com> Message-ID: I agree that the AMonoid type you describe is useful. In fact, it's going to be in base when GHC 8.6 is released: https://github.com/ghc/ghc/pull/123 On Wed, May 2, 2018 at 10:31 AM, 박신환 wrote: > Logical XOR is associative, also is XNOR. And they both have an identity > element. > > > > Hence: > > > > newtype Even = Even {getEven :: Bool} > > newtype Odd = Odd {getOdd :: Bool} > > > > instance Semigroup Even where > > (<>) = (==) -- (==) over Bool == Logical XNOR > > > > instance Semigroup Odd where > > (<>) = (/=) -- (/=) over Bool == Logical XOR > > > > instance Monoid Even where > > mempty = True > > > > instance Monoid Odd where > > mempty = False > > > > So foldMap would determine the parity of the number of Trues. > > > > > > Also, Monoid lifted by Applicative is also Monoid. This might be useful: > > > > newtype AMonoid f a = AMonoid {getAMonoid :: f a} > > > > instance (Applicative f, Semigroup a) => Semigroup (AMonoid f a) where > > (<>) = liftA2 (<>) > > > > instance (Applicative f, Monoid a) => Monoid (AMonoid f a) where > > mempty = pure mempty > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -- -Andrew Thaddeus Martin -------------- next part -------------- An HTML attachment was scrubbed... URL: From ndospark320 at naver.com Thu May 3 09:22:16 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Thu, 03 May 2018 18:22:16 +0900 Subject: =?utf-8?B?TW9ub2lkIGZvciBaaXBMaXN0?= Message-ID: As instance Alternative ZipList is defined since 4.11.0.0: instanceAlternativeZipListwhereempty=ZipList[]ZipList<|>ZipList=ZipList(xs++drop(lengthxs)ys) It seems perfectly fine to make Monoid for ZipList as followings: instance Semigroup a => Semigroup (ZipList a) where ZipList [] <> ZipList ys = ZipList ys ZipList xs <> ZipList [] = ZipList xs ZipList (x:xs) <> ZipList (y:ys) = ZipList (x <> y : ZipList xs <> ZipList ys) instance Semigroup a => Monoid (ZipList a) where mempty = ZipList [] Note that this semantic is similar to that of Maybe​. -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrew.thaddeus at gmail.com Thu May 3 12:05:24 2018 From: andrew.thaddeus at gmail.com (Andrew Martin) Date: Thu, 3 May 2018 08:05:24 -0400 Subject: Monoid for ZipList In-Reply-To: References: Message-ID: There is another possible instance. We can instead write: instance Semigroup a => Semigroup (ZipList a) where (<>) = liftA2 (<>) instance Monoid a => Monoid (ZipList a) where mempty = pure mempty This behaves differently, and it is also law-abiding. On Thu, May 3, 2018 at 5:22 AM, 박신환 wrote: > As *instance Alternative ZipList* is defined since 4.11.0.0: > > *instance Alternative ZipList where > empty = ZipList [] > ZipList xs <|> ZipList ys = ZipList (xs ++ drop (length xs ) ys * > *)* > It seems perfectly fine to make *Monoid* for *ZipList* as followings: > > > > > > > > *instance Semigroup a => Semigroup (ZipList a) where ZipList [] <> ZipList ys = ZipList ys ZipList xs <> ZipList [] = ZipList xs ZipList (x:xs) <> ZipList (y:ys) = ZipList (x <> y : ZipList xs <> ZipList ys)instance Semigroup a => Monoid (ZipList a) where mempty = ZipList []* > > Note that this semantic is similar to that of *Maybe*​. > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -- -Andrew Thaddeus Martin -------------- next part -------------- An HTML attachment was scrubbed... URL: From gershomb at gmail.com Thu May 3 15:57:27 2018 From: gershomb at gmail.com (Gershom B) Date: Thu, 3 May 2018 11:57:27 -0400 Subject: Proposal: add a foldable law Message-ID: This came up before (see the prior thread): https://mail.haskell.org/pipermail/libraries/2015-February/024943.html The thread at that time grew rather large, and only at the end did I come up with what I continue to think is a satisfactory formulation of the law. However, at that point nobody really acted to do anything about it. I would like to _formally request that the core libraries committee review_ the final version of the law as proposed, for addition to Foldable documentation: == Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, Ord), where GenericSet is otherwise fully abstract: forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). maybe True (`Foldable.elem` x) (g x) =/= False == The intuition is: "there is no general way to get an `a` out of `f a` which cannot be seen by the `Foldable` instance". The use of `GenericSet` is to handle the case of GADTs, since even parametric polymorphic functions on them may at given _already known_ types have specific behaviors. This law also works over infinite structures. It rules out "obviously wrong" instances and accepts all the instances we want to that I am aware of. My specific motivation for raising this again is that I am rather tired of people saying "well, Foldable has no laws, and it is in base, so things without laws are just fine." Foldable does a have a law we all know to obey. It just has been rather tricky to state. The above provides a decent way to state it. So we should state it. Cheers, Gershom From ndospark320 at naver.com Thu May 3 23:40:44 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Fri, 04 May 2018 08:40:44 +0900 Subject: =?utf-8?B?UmU6IE1vbm9pZCBmb3IgWmlwTGlzdA==?= In-Reply-To: <2a39c3ed6652c56e115bbb7f1f80871@cweb01.nm.nhnsystem.com> References: <2a39c3ed6652c56e115bbb7f1f80871@cweb01.nm.nhnsystem.com> Message-ID: I aim to make the semantic consistent compared to that of other type classes (here Maybe). Also note that your instance is identical to upcoming Ap, as Ap (ZipList a). I also aim to make Monoids as diverse as possible. -----Original Message----- From: "Andrew Martin" To: "박신환"; Cc: "Haskell Libraries"; Sent: 2018-05-03 (목) 21:05:24 Subject: Re: Monoid for ZipList There is another possible instance. We can instead write: instance Semigroup a => Semigroup (ZipList a) where (<>) = liftA2 (<>) instance Monoid a => Monoid (ZipList a) where mempty = pure mempty This behaves differently, and it is also law-abiding. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Fri May 4 22:04:05 2018 From: ekmett at gmail.com (Edward Kmett) Date: Fri, 4 May 2018 18:04:05 -0400 Subject: Monoid for ZipList In-Reply-To: References: <2a39c3ed6652c56e115bbb7f1f80871@cweb01.nm.nhnsystem.com> Message-ID: <07FFD10B-93A0-47BF-92DC-0893392FFD8D@gmail.com> It is worth noting that Maybe a and [a] are rather special cases. The former is the monoid you get from adjoining a unit to a semigroup. The latter is the free monoid. Most other monoids for things wrapped in an applicative are either based on the Alternative instance which inherently provides a monoidal structure or based on lifting a monoid pointwise into the data type. Here we have at least 3-4 possible, quite reasonable, monoids at play, and no real reason to choose any one of them over the others. In that situation, our general practice thus far has been to resist choosing if a choice hasn't already been made, simply because there is no real manner other than memorization / code inspection for a user to know which instance we happened to pick. I'm -1 on adding the instance proposed here. Sent from my iPhone > On May 3, 2018, at 7:40 PM, 박신환 wrote: > > I aim to make the semantic consistent compared to that of other type classes (here Maybe). > > Also note that your instance is identical to upcoming Ap, as Ap (ZipList a). I also aim to make Monoids as diverse as possible. > > > -----Original Message----- > From: "Andrew Martin" > To: "박신환"; > Cc: "Haskell Libraries"; > Sent: 2018-05-03 (목) 21:05:24 > Subject: Re: Monoid for ZipList > > There is another possible instance. We can instead write: > > instance Semigroup a => Semigroup (ZipList a) where > (<>) = liftA2 (<>) > instance Monoid a => Monoid (ZipList a) where > mempty = pure mempty > > This behaves differently, and it is also law-abiding. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From ndospark320 at naver.com Sat May 5 07:38:33 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Sat, 05 May 2018 16:38:33 +0900 Subject: =?utf-8?B?UmU6IE1vbm9pZCBmb3IgWmlwTGlzdA==?= In-Reply-To: <07FFD10B-93A0-47BF-92DC-0893392FFD8D@gmail.com> References: <2a39c3ed6652c56e115bbb7f1f80871@cweb01.nm.nhnsystem.com> <07FFD10B-93A0-47BF-92DC-0893392FFD8D@gmail.com> Message-ID: <1fd0da4c12183d7d273e2a5a36d24697@cweb20.nm.nhnsystem.com> I'm not refering that Maybe makes Monoid by adding the identity element. I'm refering that the Monoid (Maybe (First a)) have the same semantic as Alternative Maybe. So I'm suggesting that the same semantic should go to Monoid (ZipList (First a)) for Alternative ZipList. -----Original Message----- From: "Edward Kmett" To: "박신환"; Cc: "Haskell Libraries"; Sent: 2018-05-05 (토) 07:04:05 Subject: Re: Monoid for ZipList It is worth noting that Maybe a and [a] are rather special cases. The former is the monoid you get from adjoining a unit to a semigroup. The latter is the free monoid. Most other monoids for things wrapped in an applicative are either based on the Alternative instance which inherently provides a monoidal structure or based on lifting a monoid pointwise into the data type. Here we have at least 3-4 possible, quite reasonable, monoids at play, and no real reason to choose any one of them over the others. In that situation, our general practice thus far has been to resist choosing if a choice hasn't already been made, simply because there is no real manner other than memorization / code inspection for a user to know which instance we happened to pick. I'm -1 on adding the instance proposed here. Sent from my iPhone -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sat May 5 18:31:02 2018 From: ekmett at gmail.com (Edward Kmett) Date: Sat, 5 May 2018 14:31:02 -0400 Subject: Monoid over XOR or XNOR, and Monoid lifted by Applicative. In-Reply-To: <4664b84458b828b68b9b5e92fde9b3@cweb09.nm.nhnsystem.com> References: <4664b84458b828b68b9b5e92fde9b3@cweb09.nm.nhnsystem.com> Message-ID: In that same light, we're also missing packaged monoids for the bitwise (.|.), (.&.), xor (and the non-existent xnor) from Data.Bits. Bool is an instance of Bits. Extending this to these more general types you'd get: newtype And a = And { getAnd :: a } newtype Or a = Or { getOr :: a } newtype Even a = Even { getEven :: a } newtype Odd a = Odd { getOdd :: a } Once things move to arbitrary bitwise operations, Even/Odd may not be the best names, though they do perform "vertical" bitwise parity checks. While I don't have a particularly strong preference about whether those extra instances should live in Data.Monoid or Data.Bits, due to Monoid now being in Prelude, users do import Data.Monoid unqualified in rather more code than Bits. This would give me a slight preference to placing these in Data.Bits, but if one or the other would create an import cycle in base, I think it'd be fine to let that trump such a concern and force the placement. -Edward On Wed, May 2, 2018 at 10:31 AM, 박신환 wrote: > Logical XOR is associative, also is XNOR. And they both have an identity > element. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From m.farkasdyck at gmail.com Sat May 5 20:54:55 2018 From: m.farkasdyck at gmail.com (Matthew Farkas-Dyck) Date: Sat, 5 May 2018 12:54:55 -0800 Subject: Monoid over XOR or XNOR, and Monoid lifted by Applicative. In-Reply-To: References: <4664b84458b828b68b9b5e92fde9b3@cweb09.nm.nhnsystem.com> Message-ID: On 5/5/18, Edward Kmett wrote: > In that same light, we're also missing packaged monoids for the bitwise > (.|.), (.&.), xor (and the non-existent xnor) from Data.Bits. I defined a `BitSet` type in my alg package: http://hackage.haskell.org/package/alg (Building docs failed, so here is the definition: `newtype BitSet a = BitSet { bits :: a }`) The `Monoid` instance is (`False`, `xor`) (wasn't thinking about xnor, stupid me). I was also trying to define `Monoid` instances for `Min (BitSet a)` and `Max (BitSet a)` but alas, they overlap, tho `BitSet` is not `Ord` (so usual instances are useless). Maybe we want a `Lattice` class? From david.feuer at gmail.com Sat May 5 21:09:16 2018 From: david.feuer at gmail.com (David Feuer) Date: Sat, 05 May 2018 21:09:16 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: I have another idea that might be worth considering. I think it's a lot simpler than yours. Law: If t is a Foldable instance, then there must exist: 1. A Traversable instance u and 2. An injective function toTrav :: t a -> u a Such that foldMap @t = foldMapDefault . toTrav I'm pretty sure this gets at the point you're trying to make. On May 3, 2018 11:58 AM, "Gershom B" wrote: This came up before (see the prior thread): https://mail.haskell.org/pipermail/libraries/2015-February/024943.html The thread at that time grew rather large, and only at the end did I come up with what I continue to think is a satisfactory formulation of the law. However, at that point nobody really acted to do anything about it. I would like to _formally request that the core libraries committee review_ the final version of the law as proposed, for addition to Foldable documentation: == Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, Ord), where GenericSet is otherwise fully abstract: forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). maybe True (`Foldable.elem` x) (g x) =/= False == The intuition is: "there is no general way to get an `a` out of `f a` which cannot be seen by the `Foldable` instance". The use of `GenericSet` is to handle the case of GADTs, since even parametric polymorphic functions on them may at given _already known_ types have specific behaviors. This law also works over infinite structures. It rules out "obviously wrong" instances and accepts all the instances we want to that I am aware of. My specific motivation for raising this again is that I am rather tired of people saying "well, Foldable has no laws, and it is in base, so things without laws are just fine." Foldable does a have a law we all know to obey. It just has been rather tricky to state. The above provides a decent way to state it. So we should state it. Cheers, Gershom _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sat May 5 21:11:38 2018 From: david.feuer at gmail.com (David Feuer) Date: Sat, 05 May 2018 21:11:38 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Actually, requiring injectivity shouldn't be necessary. On Sat, May 5, 2018, 5:09 PM David Feuer wrote: > I have another idea that might be worth considering. I think it's a lot > simpler than yours. > > Law: If t is a Foldable instance, then there must exist: > > 1. A Traversable instance u and > 2. An injective function > toTrav :: t a -> u a > > Such that > > foldMap @t = foldMapDefault . toTrav > > I'm pretty sure this gets at the point you're trying to make. > > > On May 3, 2018 11:58 AM, "Gershom B" wrote: > > This came up before (see the prior thread): > https://mail.haskell.org/pipermail/libraries/2015-February/024943.html > > The thread at that time grew rather large, and only at the end did I > come up with what I continue to think is a satisfactory formulation of > the law. > > However, at that point nobody really acted to do anything about it. > > I would like to _formally request that the core libraries committee > review_ the final version of the law as proposed, for addition to > Foldable documentation: > > == > Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, > Ord), where GenericSet is otherwise fully abstract: > > forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). > maybe True (`Foldable.elem` x) (g x) =/= False > == > > The intuition is: "there is no general way to get an `a` out of `f a` > which cannot be seen by the `Foldable` instance". The use of > `GenericSet` is to handle the case of GADTs, since even parametric > polymorphic functions on them may at given _already known_ types have > specific behaviors. > > This law also works over infinite structures. > > It rules out "obviously wrong" instances and accepts all the instances > we want to that I am aware of. > > My specific motivation for raising this again is that I am rather > tired of people saying "well, Foldable has no laws, and it is in base, > so things without laws are just fine." Foldable does a have a law we > all know to obey. It just has been rather tricky to state. The above > provides a decent way to state it. So we should state it. > > Cheers, > Gershom > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sat May 5 21:18:07 2018 From: david.feuer at gmail.com (David Feuer) Date: Sat, 05 May 2018 21:18:07 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Let me take that back. Injectivity is necessary. And I meant foldMap @t f = foldMapDefault f . toTrav On Sat, May 5, 2018, 5:11 PM David Feuer wrote: > Actually, requiring injectivity shouldn't be necessary. > > On Sat, May 5, 2018, 5:09 PM David Feuer wrote: > >> I have another idea that might be worth considering. I think it's a lot >> simpler than yours. >> >> Law: If t is a Foldable instance, then there must exist: >> >> 1. A Traversable instance u and >> 2. An injective function >> toTrav :: t a -> u a >> >> Such that >> >> foldMap @t = foldMapDefault . toTrav >> >> I'm pretty sure this gets at the point you're trying to make. >> >> >> On May 3, 2018 11:58 AM, "Gershom B" wrote: >> >> This came up before (see the prior thread): >> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >> >> The thread at that time grew rather large, and only at the end did I >> come up with what I continue to think is a satisfactory formulation of >> the law. >> >> However, at that point nobody really acted to do anything about it. >> >> I would like to _formally request that the core libraries committee >> review_ the final version of the law as proposed, for addition to >> Foldable documentation: >> >> == >> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >> Ord), where GenericSet is otherwise fully abstract: >> >> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >> maybe True (`Foldable.elem` x) (g x) =/= False >> == >> >> The intuition is: "there is no general way to get an `a` out of `f a` >> which cannot be seen by the `Foldable` instance". The use of >> `GenericSet` is to handle the case of GADTs, since even parametric >> polymorphic functions on them may at given _already known_ types have >> specific behaviors. >> >> This law also works over infinite structures. >> >> It rules out "obviously wrong" instances and accepts all the instances >> we want to that I am aware of. >> >> My specific motivation for raising this again is that I am rather >> tired of people saying "well, Foldable has no laws, and it is in base, >> so things without laws are just fine." Foldable does a have a law we >> all know to obey. It just has been rather tricky to state. The above >> provides a decent way to state it. So we should state it. >> >> Cheers, >> Gershom >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sat May 5 21:51:06 2018 From: ekmett at gmail.com (Edward Kmett) Date: Sat, 5 May 2018 17:51:06 -0400 Subject: Monoid over XOR or XNOR, and Monoid lifted by Applicative. In-Reply-To: References: <4664b84458b828b68b9b5e92fde9b3@cweb09.nm.nhnsystem.com> Message-ID: There are several packagings of lattices and semilattices strewn across hackage, and not much convergence on any single one. Sent from my iPhone > On May 5, 2018, at 4:54 PM, Matthew Farkas-Dyck wrote: > >> On 5/5/18, Edward Kmett wrote: >> In that same light, we're also missing packaged monoids for the bitwise >> (.|.), (.&.), xor (and the non-existent xnor) from Data.Bits. > > I defined a `BitSet` type in my alg package: > http://hackage.haskell.org/package/alg > (Building docs failed, so here is the definition: `newtype BitSet a = > BitSet { bits :: a }`) > > The `Monoid` instance is (`False`, `xor`) (wasn't thinking about xnor, > stupid me). > > I was also trying to define `Monoid` instances for `Min (BitSet a)` > and `Max (BitSet a)` but alas, they overlap, tho `BitSet` is not `Ord` > (so usual instances are useless). > > Maybe we want a `Lattice` class? From gershomb at gmail.com Sat May 5 22:13:51 2018 From: gershomb at gmail.com (Gershom B) Date: Sat, 5 May 2018 18:13:51 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Hmm… I think this works, and specifies the same law. Nice. Assuming I’m not wrong about that, I’m happy with either version, and will leave it to the committee to decide. Best, Gershom On May 5, 2018 at 5:18:29 PM, David Feuer (david.feuer at gmail.com) wrote: Let me take that back. Injectivity is necessary. And I meant     foldMap @t f = foldMapDefault f . toTrav On Sat, May 5, 2018, 5:11 PM David Feuer wrote: Actually, requiring injectivity shouldn't be necessary. On Sat, May 5, 2018, 5:09 PM David Feuer wrote: I have another idea that might be worth considering. I think it's a lot simpler than yours. Law: If t is a Foldable instance, then there must exist: 1. A Traversable instance u and 2. An injective function        toTrav :: t a -> u a Such that     foldMap @t = foldMapDefault . toTrav I'm pretty sure this gets at the point you're trying to make. On May 3, 2018 11:58 AM, "Gershom B" wrote: This came up before (see the prior thread): https://mail.haskell.org/pipermail/libraries/2015-February/024943.html The thread at that time grew rather large, and only at the end did I come up with what I continue to think is a satisfactory formulation of the law. However, at that point nobody really acted to do anything about it. I would like to _formally request that the core libraries committee review_ the final version of the law as proposed, for addition to Foldable documentation: == Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, Ord), where GenericSet is otherwise fully abstract: forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). maybe True (`Foldable.elem` x) (g x) =/= False == The intuition is: "there is no general way to get an `a` out of `f a` which cannot be seen by the `Foldable` instance". The use of `GenericSet` is to handle the case of GADTs, since even parametric polymorphic functions on them may at given _already known_ types have specific behaviors. This law also works over infinite structures. It rules out "obviously wrong" instances and accepts all the instances we want to that I am aware of. My specific motivation for raising this again is that I am rather tired of people saying "well, Foldable has no laws, and it is in base, so things without laws are just fine." Foldable does a have a law we all know to obey. It just has been rather tricky to state. The above provides a decent way to state it. So we should state it. Cheers, Gershom _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sat May 5 22:22:52 2018 From: david.feuer at gmail.com (David Feuer) Date: Sat, 05 May 2018 22:22:52 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: You'll have to email the committee if you want them to consider anything. The law I suggested is rather stronger than yours, but I think it's probably closer to what you really meant. Neither option prevents strange GADTy instances, but I suspect that's a fundamental limitation of Foldable. On Sat, May 5, 2018, 6:13 PM Gershom B wrote: > Hmm… I think this works, and specifies the same law. Nice. Assuming I’m > not wrong about that, I’m happy with either version, and will leave it to > the committee to decide. > > Best, > Gershom > > On May 5, 2018 at 5:18:29 PM, David Feuer (david.feuer at gmail.com) wrote: > > Let me take that back. Injectivity is necessary. And I meant > > foldMap @t f = foldMapDefault f . toTrav > > On Sat, May 5, 2018, 5:11 PM David Feuer wrote: > >> Actually, requiring injectivity shouldn't be necessary. >> >> On Sat, May 5, 2018, 5:09 PM David Feuer wrote: >> >>> I have another idea that might be worth considering. I think it's a lot >>> simpler than yours. >>> >>> Law: If t is a Foldable instance, then there must exist: >>> >>> 1. A Traversable instance u and >>> 2. An injective function >>> toTrav :: t a -> u a >>> >>> Such that >>> >>> foldMap @t = foldMapDefault . toTrav >>> >>> I'm pretty sure this gets at the point you're trying to make. >>> >>> >>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>> >>> This came up before (see the prior thread): >>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>> >>> The thread at that time grew rather large, and only at the end did I >>> come up with what I continue to think is a satisfactory formulation of >>> the law. >>> >>> However, at that point nobody really acted to do anything about it. >>> >>> I would like to _formally request that the core libraries committee >>> review_ the final version of the law as proposed, for addition to >>> Foldable documentation: >>> >>> == >>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>> Ord), where GenericSet is otherwise fully abstract: >>> >>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>> maybe True (`Foldable.elem` x) (g x) =/= False >>> == >>> >>> The intuition is: "there is no general way to get an `a` out of `f a` >>> which cannot be seen by the `Foldable` instance". The use of >>> `GenericSet` is to handle the case of GADTs, since even parametric >>> polymorphic functions on them may at given _already known_ types have >>> specific behaviors. >>> >>> This law also works over infinite structures. >>> >>> It rules out "obviously wrong" instances and accepts all the instances >>> we want to that I am aware of. >>> >>> My specific motivation for raising this again is that I am rather >>> tired of people saying "well, Foldable has no laws, and it is in base, >>> so things without laws are just fine." Foldable does a have a law we >>> all know to obey. It just has been rather tricky to state. The above >>> provides a decent way to state it. So we should state it. >>> >>> Cheers, >>> Gershom >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> >>> _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gershomb at gmail.com Sat May 5 22:44:56 2018 From: gershomb at gmail.com (Gershom B) Date: Sat, 5 May 2018 15:44:56 -0700 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: As per: https://wiki.haskell.org/Core_Libraries_Committee emailing libraries@ should suffice. But in the case it doesn’t, I’m now ccing the committee alias directly as well. The law you suggested does not seem to be generally stronger than mine, but I would be interested in a counterexample if you can produce one[1]. I agree that “strange GADTy instances” are not ruled out, but I’m not sure if I’d consider it a limitation of Foldable, but more a characteristic of GADTs that isn’t per-se wrong, although it sometimes is counterintuitive :-) Best, Gershom [1] If one is to be found, one would think it’d have to do with GADTs. But I think GADTs are flexible enough that one could still provide an injection from a GADT without traversable GADT with traversable such that whatever weird stuff occurs in the former still occurs in the latter. On May 5, 2018 at 6:23:04 PM, David Feuer (david.feuer at gmail.com) wrote: You'll have to email the committee if you want them to consider anything. The law I suggested is rather stronger than yours, but I think it's probably closer to what you really meant. Neither option prevents strange GADTy instances, but I suspect that's a fundamental limitation of Foldable. On Sat, May 5, 2018, 6:13 PM Gershom B wrote: > Hmm… I think this works, and specifies the same law. Nice. Assuming I’m > not wrong about that, I’m happy with either version, and will leave it to > the committee to decide. > > Best, > Gershom > > On May 5, 2018 at 5:18:29 PM, David Feuer (david.feuer at gmail.com) wrote: > > Let me take that back. Injectivity is necessary. And I meant > > foldMap @t f = foldMapDefault f . toTrav > > On Sat, May 5, 2018, 5:11 PM David Feuer wrote: > >> Actually, requiring injectivity shouldn't be necessary. >> >> On Sat, May 5, 2018, 5:09 PM David Feuer wrote: >> >>> I have another idea that might be worth considering. I think it's a lot >>> simpler than yours. >>> >>> Law: If t is a Foldable instance, then there must exist: >>> >>> 1. A Traversable instance u and >>> 2. An injective function >>> toTrav :: t a -> u a >>> >>> Such that >>> >>> foldMap @t = foldMapDefault . toTrav >>> >>> I'm pretty sure this gets at the point you're trying to make. >>> >>> >>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>> >>> This came up before (see the prior thread): >>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>> >>> The thread at that time grew rather large, and only at the end did I >>> come up with what I continue to think is a satisfactory formulation of >>> the law. >>> >>> However, at that point nobody really acted to do anything about it. >>> >>> I would like to _formally request that the core libraries committee >>> review_ the final version of the law as proposed, for addition to >>> Foldable documentation: >>> >>> == >>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>> Ord), where GenericSet is otherwise fully abstract: >>> >>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>> maybe True (`Foldable.elem` x) (g x) =/= False >>> == >>> >>> The intuition is: "there is no general way to get an `a` out of `f a` >>> which cannot be seen by the `Foldable` instance". The use of >>> `GenericSet` is to handle the case of GADTs, since even parametric >>> polymorphic functions on them may at given _already known_ types have >>> specific behaviors. >>> >>> This law also works over infinite structures. >>> >>> It rules out "obviously wrong" instances and accepts all the instances >>> we want to that I am aware of. >>> >>> My specific motivation for raising this again is that I am rather >>> tired of people saying "well, Foldable has no laws, and it is in base, >>> so things without laws are just fine." Foldable does a have a law we >>> all know to obey. It just has been rather tricky to state. The above >>> provides a decent way to state it. So we should state it. >>> >>> Cheers, >>> Gershom >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> >>> _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sat May 5 22:46:42 2018 From: david.feuer at gmail.com (David Feuer) Date: Sat, 05 May 2018 22:46:42 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Okay, I'm not actually sure mine is stronger, but it's definitely easier to understand! On Sat, May 5, 2018, 6:44 PM Gershom B wrote: > As per: https://wiki.haskell.org/Core_Libraries_Committee emailing > libraries@ should suffice. But in the case it doesn’t, I’m now ccing the > committee alias directly as well. > > The law you suggested does not seem to be generally stronger than mine, > but I would be interested in a counterexample if you can produce one[1]. I > agree that “strange GADTy instances” are not ruled out, but I’m not sure if > I’d consider it a limitation of Foldable, but more a characteristic of > GADTs that isn’t per-se wrong, although it sometimes is counterintuitive :-) > > Best, > Gershom > > [1] If one is to be found, one would think it’d have to do with GADTs. But > I think GADTs are flexible enough that one could still provide an injection > from a GADT without traversable GADT with traversable such that whatever > weird stuff occurs in the former still occurs in the latter. > > On May 5, 2018 at 6:23:04 PM, David Feuer (david.feuer at gmail.com) wrote: > > You'll have to email the committee if you want them to consider anything. > The law I suggested is rather stronger than yours, but I think it's > probably closer to what you really meant. Neither option prevents strange > GADTy instances, but I suspect that's a fundamental limitation of Foldable. > > On Sat, May 5, 2018, 6:13 PM Gershom B wrote: > >> Hmm… I think this works, and specifies the same law. Nice. Assuming I’m >> not wrong about that, I’m happy with either version, and will leave it to >> the committee to decide. >> >> Best, >> Gershom >> >> On May 5, 2018 at 5:18:29 PM, David Feuer (david.feuer at gmail.com) wrote: >> >> Let me take that back. Injectivity is necessary. And I meant >> >> foldMap @t f = foldMapDefault f . toTrav >> >> On Sat, May 5, 2018, 5:11 PM David Feuer wrote: >> >>> Actually, requiring injectivity shouldn't be necessary. >>> >>> On Sat, May 5, 2018, 5:09 PM David Feuer wrote: >>> >>>> I have another idea that might be worth considering. I think it's a lot >>>> simpler than yours. >>>> >>>> Law: If t is a Foldable instance, then there must exist: >>>> >>>> 1. A Traversable instance u and >>>> 2. An injective function >>>> toTrav :: t a -> u a >>>> >>>> Such that >>>> >>>> foldMap @t = foldMapDefault . toTrav >>>> >>>> I'm pretty sure this gets at the point you're trying to make. >>>> >>>> >>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>> >>>> This came up before (see the prior thread): >>>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>>> >>>> The thread at that time grew rather large, and only at the end did I >>>> come up with what I continue to think is a satisfactory formulation of >>>> the law. >>>> >>>> However, at that point nobody really acted to do anything about it. >>>> >>>> I would like to _formally request that the core libraries committee >>>> review_ the final version of the law as proposed, for addition to >>>> Foldable documentation: >>>> >>>> == >>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>> Ord), where GenericSet is otherwise fully abstract: >>>> >>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>> == >>>> >>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>> which cannot be seen by the `Foldable` instance". The use of >>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>> polymorphic functions on them may at given _already known_ types have >>>> specific behaviors. >>>> >>>> This law also works over infinite structures. >>>> >>>> It rules out "obviously wrong" instances and accepts all the instances >>>> we want to that I am aware of. >>>> >>>> My specific motivation for raising this again is that I am rather >>>> tired of people saying "well, Foldable has no laws, and it is in base, >>>> so things without laws are just fine." Foldable does a have a law we >>>> all know to obey. It just has been rather tricky to state. The above >>>> provides a decent way to state it. So we should state it. >>>> >>>> Cheers, >>>> Gershom >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >>>> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sat May 5 22:56:32 2018 From: david.feuer at gmail.com (David Feuer) Date: Sat, 05 May 2018 22:56:32 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Ah, actually, I think mine *is* stronger, because it can say more about infinite structures. On Sat, May 5, 2018, 6:46 PM David Feuer wrote: > Okay, I'm not actually sure mine is stronger, but it's definitely easier > to understand! > > On Sat, May 5, 2018, 6:44 PM Gershom B wrote: > >> As per: https://wiki.haskell.org/Core_Libraries_Committee emailing >> libraries@ should suffice. But in the case it doesn’t, I’m now ccing the >> committee alias directly as well. >> >> The law you suggested does not seem to be generally stronger than mine, >> but I would be interested in a counterexample if you can produce one[1]. I >> agree that “strange GADTy instances” are not ruled out, but I’m not sure if >> I’d consider it a limitation of Foldable, but more a characteristic of >> GADTs that isn’t per-se wrong, although it sometimes is counterintuitive :-) >> >> Best, >> Gershom >> >> [1] If one is to be found, one would think it’d have to do with GADTs. >> But I think GADTs are flexible enough that one could still provide an >> injection from a GADT without traversable GADT with traversable such that >> whatever weird stuff occurs in the former still occurs in the latter. >> >> On May 5, 2018 at 6:23:04 PM, David Feuer (david.feuer at gmail.com) wrote: >> >> You'll have to email the committee if you want them to consider anything. >> The law I suggested is rather stronger than yours, but I think it's >> probably closer to what you really meant. Neither option prevents strange >> GADTy instances, but I suspect that's a fundamental limitation of Foldable. >> >> On Sat, May 5, 2018, 6:13 PM Gershom B wrote: >> >>> Hmm… I think this works, and specifies the same law. Nice. Assuming I’m >>> not wrong about that, I’m happy with either version, and will leave it to >>> the committee to decide. >>> >>> Best, >>> Gershom >>> >>> On May 5, 2018 at 5:18:29 PM, David Feuer (david.feuer at gmail.com) wrote: >>> >>> Let me take that back. Injectivity is necessary. And I meant >>> >>> foldMap @t f = foldMapDefault f . toTrav >>> >>> On Sat, May 5, 2018, 5:11 PM David Feuer wrote: >>> >>>> Actually, requiring injectivity shouldn't be necessary. >>>> >>>> On Sat, May 5, 2018, 5:09 PM David Feuer wrote: >>>> >>>>> I have another idea that might be worth considering. I think it's a >>>>> lot simpler than yours. >>>>> >>>>> Law: If t is a Foldable instance, then there must exist: >>>>> >>>>> 1. A Traversable instance u and >>>>> 2. An injective function >>>>> toTrav :: t a -> u a >>>>> >>>>> Such that >>>>> >>>>> foldMap @t = foldMapDefault . toTrav >>>>> >>>>> I'm pretty sure this gets at the point you're trying to make. >>>>> >>>>> >>>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>>> >>>>> This came up before (see the prior thread): >>>>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>>>> >>>>> The thread at that time grew rather large, and only at the end did I >>>>> come up with what I continue to think is a satisfactory formulation of >>>>> the law. >>>>> >>>>> However, at that point nobody really acted to do anything about it. >>>>> >>>>> I would like to _formally request that the core libraries committee >>>>> review_ the final version of the law as proposed, for addition to >>>>> Foldable documentation: >>>>> >>>>> == >>>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>>> Ord), where GenericSet is otherwise fully abstract: >>>>> >>>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>>> == >>>>> >>>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>>> which cannot be seen by the `Foldable` instance". The use of >>>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>>> polymorphic functions on them may at given _already known_ types have >>>>> specific behaviors. >>>>> >>>>> This law also works over infinite structures. >>>>> >>>>> It rules out "obviously wrong" instances and accepts all the instances >>>>> we want to that I am aware of. >>>>> >>>>> My specific motivation for raising this again is that I am rather >>>>> tired of people saying "well, Foldable has no laws, and it is in base, >>>>> so things without laws are just fine." Foldable does a have a law we >>>>> all know to obey. It just has been rather tricky to state. The above >>>>> provides a decent way to state it. So we should state it. >>>>> >>>>> Cheers, >>>>> Gershom >>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>>>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From ndospark320 at naver.com Sun May 6 00:40:19 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Sun, 06 May 2018 09:40:19 +0900 Subject: =?utf-8?B?TW9ub2lkIG92ZXIgcmVjaXByb2NhbCBvZiByZWNpcHJvY2FsIHN1bQ==?= Message-ID: e.g. Parallel resistors, serial capacitors, parallel inductors. newtype RecipSum a = RecipSum {getRecipSum :: a} instance Fractional a => Semigroup (RecipSum a) where RecipSum x <> RecipSum y = RecipSum (recip (recip x + recip y)) sconcat (x :| xs) = mconcat (x : xs). stimes n (RecipSum x) = RecipSum (x / fromIntegral n) instance Fractional a => Monoid (ResipSum a) where mempty = RecipSum (1 / 0) mconcat xs = RecipSum (recip . getSum $ foldMap (Sum . recip . getRecipSum) xs) -------------- next part -------------- An HTML attachment was scrubbed... URL: From ndospark320 at naver.com Sun May 6 00:52:09 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Sun, 06 May 2018 09:52:09 +0900 Subject: =?utf-8?B?TW9ub2lkIG92ZXIgcmVjaXByb2NhbCBvZiByZWNpcHJvY2FsIHN1bQ==?= In-Reply-To: References: Message-ID: <136648cc88d941528d2192abfd9905f@cweb22.nm.nhnsystem.com> e.g. Parallel resistors, serial capacitors, parallel inductors. EDIT: Corrected typo. newtype RecipSum a = RecipSum {getRecipSum :: a} instance Fractional a => Semigroup (RecipSum a) where RecipSum x <> RecipSum y = RecipSum (recip (recip x + recip y)) sconcat (x :| xs) = mconcat (x : xs) stimes n (RecipSum x) = RecipSum (x / fromIntegral n) instance Fractional a => Monoid (RecipSum a) where mempty = RecipSum (1 / 0) mconcat xs = RecipSum (recip . getSum $ foldMap (Sum . recip . getRecipSum) xs) -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sun May 6 02:18:10 2018 From: david.feuer at gmail.com (David Feuer) Date: Sun, 06 May 2018 02:18:10 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: My law, unlike yours, also prohibits Foldable IO. On Sat, May 5, 2018, 6:56 PM David Feuer wrote: > Ah, actually, I think mine *is* stronger, because it can say more about > infinite structures. > > On Sat, May 5, 2018, 6:46 PM David Feuer wrote: > >> Okay, I'm not actually sure mine is stronger, but it's definitely easier >> to understand! >> >> On Sat, May 5, 2018, 6:44 PM Gershom B wrote: >> >>> As per: https://wiki.haskell.org/Core_Libraries_Committee emailing >>> libraries@ should suffice. But in the case it doesn’t, I’m now ccing >>> the committee alias directly as well. >>> >>> The law you suggested does not seem to be generally stronger than mine, >>> but I would be interested in a counterexample if you can produce one[1]. I >>> agree that “strange GADTy instances” are not ruled out, but I’m not sure if >>> I’d consider it a limitation of Foldable, but more a characteristic of >>> GADTs that isn’t per-se wrong, although it sometimes is counterintuitive :-) >>> >>> Best, >>> Gershom >>> >>> [1] If one is to be found, one would think it’d have to do with GADTs. >>> But I think GADTs are flexible enough that one could still provide an >>> injection from a GADT without traversable GADT with traversable such that >>> whatever weird stuff occurs in the former still occurs in the latter. >>> >>> On May 5, 2018 at 6:23:04 PM, David Feuer (david.feuer at gmail.com) wrote: >>> >>> You'll have to email the committee if you want them to consider >>> anything. The law I suggested is rather stronger than yours, but I think >>> it's probably closer to what you really meant. Neither option prevents >>> strange GADTy instances, but I suspect that's a fundamental limitation of >>> Foldable. >>> >>> On Sat, May 5, 2018, 6:13 PM Gershom B wrote: >>> >>>> Hmm… I think this works, and specifies the same law. Nice. Assuming I’m >>>> not wrong about that, I’m happy with either version, and will leave it to >>>> the committee to decide. >>>> >>>> Best, >>>> Gershom >>>> >>>> On May 5, 2018 at 5:18:29 PM, David Feuer (david.feuer at gmail.com) >>>> wrote: >>>> >>>> Let me take that back. Injectivity is necessary. And I meant >>>> >>>> foldMap @t f = foldMapDefault f . toTrav >>>> >>>> On Sat, May 5, 2018, 5:11 PM David Feuer wrote: >>>> >>>>> Actually, requiring injectivity shouldn't be necessary. >>>>> >>>>> On Sat, May 5, 2018, 5:09 PM David Feuer >>>>> wrote: >>>>> >>>>>> I have another idea that might be worth considering. I think it's a >>>>>> lot simpler than yours. >>>>>> >>>>>> Law: If t is a Foldable instance, then there must exist: >>>>>> >>>>>> 1. A Traversable instance u and >>>>>> 2. An injective function >>>>>> toTrav :: t a -> u a >>>>>> >>>>>> Such that >>>>>> >>>>>> foldMap @t = foldMapDefault . toTrav >>>>>> >>>>>> I'm pretty sure this gets at the point you're trying to make. >>>>>> >>>>>> >>>>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>>>> >>>>>> This came up before (see the prior thread): >>>>>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>>>>> >>>>>> The thread at that time grew rather large, and only at the end did I >>>>>> come up with what I continue to think is a satisfactory formulation of >>>>>> the law. >>>>>> >>>>>> However, at that point nobody really acted to do anything about it. >>>>>> >>>>>> I would like to _formally request that the core libraries committee >>>>>> review_ the final version of the law as proposed, for addition to >>>>>> Foldable documentation: >>>>>> >>>>>> == >>>>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>>>> Ord), where GenericSet is otherwise fully abstract: >>>>>> >>>>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>>>> == >>>>>> >>>>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>>>> which cannot be seen by the `Foldable` instance". The use of >>>>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>>>> polymorphic functions on them may at given _already known_ types have >>>>>> specific behaviors. >>>>>> >>>>>> This law also works over infinite structures. >>>>>> >>>>>> It rules out "obviously wrong" instances and accepts all the instances >>>>>> we want to that I am aware of. >>>>>> >>>>>> My specific motivation for raising this again is that I am rather >>>>>> tired of people saying "well, Foldable has no laws, and it is in base, >>>>>> so things without laws are just fine." Foldable does a have a law we >>>>>> all know to obey. It just has been rather tricky to state. The above >>>>>> provides a decent way to state it. So we should state it. >>>>>> >>>>>> Cheers, >>>>>> Gershom >>>>>> _______________________________________________ >>>>>> Libraries mailing list >>>>>> Libraries at haskell.org >>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> >>>>>> >>>>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From gershomb at gmail.com Sun May 6 02:36:58 2018 From: gershomb at gmail.com (Gershom B) Date: Sat, 5 May 2018 22:36:58 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: I think you’re wrong on both counts. The “quantification law” (i.e. what i suggest) permits reasoning on infinite structures. It is carefully written to that end. Also, the “injection law” (i.e. what you suggest) allows the same nullary instance as the quantification law for IO. In particular: data HideIO a   where HideIO :: forall b. IO b -> HideIO a equipped with the trivial/nullary traversable instance. toTrav  = HideIO  this gives a “lawful” foldable with toList = [], just as with the “quantification law”. Note that you can’t do this in general (otherwise the law would be useless). In particular, a type data Hide a    where Hide :: forall b. b -> Hide a would not give `Hide` as a genuine injection, since we couldn’t actually distinguish the application to different values. However, because we’re in IO, we can recover a genuine injection, by various means — some more nefarious than others. The two laws really _are_ saying almost the same things. The quantification in the first version is nearly an extremely-spelled-out version of the injectivity condition. —Gershom On May 5, 2018 at 10:18:34 PM, David Feuer (david.feuer at gmail.com) wrote: My law, unlike yours, also prohibits Foldable IO. On Sat, May 5, 2018, 6:56 PM David Feuer wrote: Ah, actually, I think mine *is* stronger, because it can say more about infinite structures. On Sat, May 5, 2018, 6:46 PM David Feuer wrote: Okay, I'm not actually sure mine is stronger, but it's definitely easier to understand! On Sat, May 5, 2018, 6:44 PM Gershom B wrote: As per: https://wiki.haskell.org/Core_Libraries_Committee emailing libraries@ should suffice. But in the case it doesn’t, I’m now ccing the committee alias directly as well. The law you suggested does not seem to be generally stronger than mine, but I would be interested in a counterexample if you can produce one[1]. I agree that “strange GADTy instances” are not ruled out, but I’m not sure if I’d consider it a limitation of Foldable, but more a characteristic of GADTs that isn’t per-se wrong, although it sometimes is counterintuitive :-) Best, Gershom [1] If one is to be found, one would think it’d have to do with GADTs. But I think GADTs are flexible enough that one could still provide an injection from a GADT without traversable GADT with traversable such that whatever weird stuff occurs in the former still occurs in the latter. On May 5, 2018 at 6:23:04 PM, David Feuer (david.feuer at gmail.com) wrote: You'll have to email the committee if you want them to consider anything. The law I suggested is rather stronger than yours, but I think it's probably closer to what you really meant. Neither option prevents strange GADTy instances, but I suspect that's a fundamental limitation of Foldable. On Sat, May 5, 2018, 6:13 PM Gershom B wrote: Hmm… I think this works, and specifies the same law. Nice. Assuming I’m not wrong about that, I’m happy with either version, and will leave it to the committee to decide. Best, Gershom On May 5, 2018 at 5:18:29 PM, David Feuer (david.feuer at gmail.com) wrote: Let me take that back. Injectivity is necessary. And I meant     foldMap @t f = foldMapDefault f . toTrav On Sat, May 5, 2018, 5:11 PM David Feuer wrote: Actually, requiring injectivity shouldn't be necessary. On Sat, May 5, 2018, 5:09 PM David Feuer wrote: I have another idea that might be worth considering. I think it's a lot simpler than yours. Law: If t is a Foldable instance, then there must exist: 1. A Traversable instance u and 2. An injective function        toTrav :: t a -> u a Such that     foldMap @t = foldMapDefault . toTrav I'm pretty sure this gets at the point you're trying to make. On May 3, 2018 11:58 AM, "Gershom B" wrote: This came up before (see the prior thread): https://mail.haskell.org/pipermail/libraries/2015-February/024943.html The thread at that time grew rather large, and only at the end did I come up with what I continue to think is a satisfactory formulation of the law. However, at that point nobody really acted to do anything about it. I would like to _formally request that the core libraries committee review_ the final version of the law as proposed, for addition to Foldable documentation: == Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, Ord), where GenericSet is otherwise fully abstract: forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). maybe True (`Foldable.elem` x) (g x) =/= False == The intuition is: "there is no general way to get an `a` out of `f a` which cannot be seen by the `Foldable` instance". The use of `GenericSet` is to handle the case of GADTs, since even parametric polymorphic functions on them may at given _already known_ types have specific behaviors. This law also works over infinite structures. It rules out "obviously wrong" instances and accepts all the instances we want to that I am aware of. My specific motivation for raising this again is that I am rather tired of people saying "well, Foldable has no laws, and it is in base, so things without laws are just fine." Foldable does a have a law we all know to obey. It just has been rather tricky to state. The above provides a decent way to state it. So we should state it. Cheers, Gershom _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sun May 6 02:37:17 2018 From: ekmett at gmail.com (Edward Kmett) Date: Sat, 5 May 2018 22:37:17 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: I actually don't have any real objection to something like David's version of the law. Unlike the GenericSet version, it at first glance feels like it handles the GADT-based cases without tripping on the cases where the law doesn't apply because it doesn't just doesn't type check. That had been my major objection to Gershom's law. -Edward On Sat, May 5, 2018 at 5:09 PM, David Feuer wrote: > I have another idea that might be worth considering. I think it's a lot > simpler than yours. > > Law: If t is a Foldable instance, then there must exist: > > 1. A Traversable instance u and > 2. An injective function > toTrav :: t a -> u a > > Such that > > foldMap @t = foldMapDefault . toTrav > > I'm pretty sure this gets at the point you're trying to make. > > > On May 3, 2018 11:58 AM, "Gershom B" wrote: > > This came up before (see the prior thread): > https://mail.haskell.org/pipermail/libraries/2015-February/024943.html > > The thread at that time grew rather large, and only at the end did I > come up with what I continue to think is a satisfactory formulation of > the law. > > However, at that point nobody really acted to do anything about it. > > I would like to _formally request that the core libraries committee > review_ the final version of the law as proposed, for addition to > Foldable documentation: > > == > Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, > Ord), where GenericSet is otherwise fully abstract: > > forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). > maybe True (`Foldable.elem` x) (g x) =/= False > == > > The intuition is: "there is no general way to get an `a` out of `f a` > which cannot be seen by the `Foldable` instance". The use of > `GenericSet` is to handle the case of GADTs, since even parametric > polymorphic functions on them may at given _already known_ types have > specific behaviors. > > This law also works over infinite structures. > > It rules out "obviously wrong" instances and accepts all the instances > we want to that I am aware of. > > My specific motivation for raising this again is that I am rather > tired of people saying "well, Foldable has no laws, and it is in base, > so things without laws are just fine." Foldable does a have a law we > all know to obey. It just has been rather tricky to state. The above > provides a decent way to state it. So we should state it. > > Cheers, > Gershom > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sun May 6 02:43:33 2018 From: david.feuer at gmail.com (David Feuer) Date: Sun, 06 May 2018 02:43:33 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: HideIO is devious, but I'd argue it's not a proper injection. In particular, HideIO (fmap g m) is indistinguishable from HideIO m, even if fmap g m is distinguishable from m. Your law doesn't blow up for infinite structures (your care wasn't for nothing) but it doesn't say very much about them. On Sat, May 5, 2018, 10:37 PM Gershom B wrote: > I think you’re wrong on both counts. The “quantification law” (i.e. what i > suggest) permits reasoning on infinite structures. It is carefully written > to that end. Also, the “injection law” (i.e. what you suggest) allows the > same nullary instance as the quantification law for IO. > > In particular: > > data HideIO a > where HideIO :: forall b. IO b -> HideIO a > > equipped with the trivial/nullary traversable instance. > > toTrav = HideIO > > this gives a “lawful” foldable with toList = [], just as with the > “quantification law”. > > Note that you can’t do this in general (otherwise the law would be > useless). In particular, a type > > data Hide a > where Hide :: forall b. b -> Hide a > > would not give `Hide` as a genuine injection, since we couldn’t actually > distinguish the application to different values. > > However, because we’re in IO, we can recover a genuine injection, by > various means — some more nefarious than others. > > The two laws really _are_ saying almost the same things. The > quantification in the first version is nearly an extremely-spelled-out > version of the injectivity condition. > > —Gershom > > > On May 5, 2018 at 10:18:34 PM, David Feuer (david.feuer at gmail.com) wrote: > > My law, unlike yours, also prohibits Foldable IO. > > On Sat, May 5, 2018, 6:56 PM David Feuer wrote: > >> Ah, actually, I think mine *is* stronger, because it can say more about >> infinite structures. >> >> On Sat, May 5, 2018, 6:46 PM David Feuer wrote: >> >>> Okay, I'm not actually sure mine is stronger, but it's definitely easier >>> to understand! >>> >>> On Sat, May 5, 2018, 6:44 PM Gershom B wrote: >>> >>>> As per: https://wiki.haskell.org/Core_Libraries_Committee emailing >>>> libraries@ should suffice. But in the case it doesn’t, I’m now ccing >>>> the committee alias directly as well. >>>> >>>> The law you suggested does not seem to be generally stronger than mine, >>>> but I would be interested in a counterexample if you can produce one[1]. I >>>> agree that “strange GADTy instances” are not ruled out, but I’m not sure if >>>> I’d consider it a limitation of Foldable, but more a characteristic of >>>> GADTs that isn’t per-se wrong, although it sometimes is counterintuitive :-) >>>> >>>> Best, >>>> Gershom >>>> >>>> [1] If one is to be found, one would think it’d have to do with GADTs. >>>> But I think GADTs are flexible enough that one could still provide an >>>> injection from a GADT without traversable GADT with traversable such that >>>> whatever weird stuff occurs in the former still occurs in the latter. >>>> >>>> On May 5, 2018 at 6:23:04 PM, David Feuer (david.feuer at gmail.com) >>>> wrote: >>>> >>>> You'll have to email the committee if you want them to consider >>>> anything. The law I suggested is rather stronger than yours, but I think >>>> it's probably closer to what you really meant. Neither option prevents >>>> strange GADTy instances, but I suspect that's a fundamental limitation of >>>> Foldable. >>>> >>>> On Sat, May 5, 2018, 6:13 PM Gershom B wrote: >>>> >>>>> Hmm… I think this works, and specifies the same law. Nice. Assuming >>>>> I’m not wrong about that, I’m happy with either version, and will leave it >>>>> to the committee to decide. >>>>> >>>>> Best, >>>>> Gershom >>>>> >>>>> On May 5, 2018 at 5:18:29 PM, David Feuer (david.feuer at gmail.com) >>>>> wrote: >>>>> >>>>> Let me take that back. Injectivity is necessary. And I meant >>>>> >>>>> foldMap @t f = foldMapDefault f . toTrav >>>>> >>>>> On Sat, May 5, 2018, 5:11 PM David Feuer >>>>> wrote: >>>>> >>>>>> Actually, requiring injectivity shouldn't be necessary. >>>>>> >>>>>> On Sat, May 5, 2018, 5:09 PM David Feuer >>>>>> wrote: >>>>>> >>>>>>> I have another idea that might be worth considering. I think it's a >>>>>>> lot simpler than yours. >>>>>>> >>>>>>> Law: If t is a Foldable instance, then there must exist: >>>>>>> >>>>>>> 1. A Traversable instance u and >>>>>>> 2. An injective function >>>>>>> toTrav :: t a -> u a >>>>>>> >>>>>>> Such that >>>>>>> >>>>>>> foldMap @t = foldMapDefault . toTrav >>>>>>> >>>>>>> I'm pretty sure this gets at the point you're trying to make. >>>>>>> >>>>>>> >>>>>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>>>>> >>>>>>> This came up before (see the prior thread): >>>>>>> >>>>>>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>>>>>> >>>>>>> The thread at that time grew rather large, and only at the end did I >>>>>>> come up with what I continue to think is a satisfactory formulation >>>>>>> of >>>>>>> the law. >>>>>>> >>>>>>> However, at that point nobody really acted to do anything about it. >>>>>>> >>>>>>> I would like to _formally request that the core libraries committee >>>>>>> review_ the final version of the law as proposed, for addition to >>>>>>> Foldable documentation: >>>>>>> >>>>>>> == >>>>>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>>>>> Ord), where GenericSet is otherwise fully abstract: >>>>>>> >>>>>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>>>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>>>>> == >>>>>>> >>>>>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>>>>> which cannot be seen by the `Foldable` instance". The use of >>>>>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>>>>> polymorphic functions on them may at given _already known_ types have >>>>>>> specific behaviors. >>>>>>> >>>>>>> This law also works over infinite structures. >>>>>>> >>>>>>> It rules out "obviously wrong" instances and accepts all the >>>>>>> instances >>>>>>> we want to that I am aware of. >>>>>>> >>>>>>> My specific motivation for raising this again is that I am rather >>>>>>> tired of people saying "well, Foldable has no laws, and it is in >>>>>>> base, >>>>>>> so things without laws are just fine." Foldable does a have a law we >>>>>>> all know to obey. It just has been rather tricky to state. The above >>>>>>> provides a decent way to state it. So we should state it. >>>>>>> >>>>>>> Cheers, >>>>>>> Gershom >>>>>>> _______________________________________________ >>>>>>> Libraries mailing list >>>>>>> Libraries at haskell.org >>>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>> >>>>>>> >>>>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gershomb at gmail.com Sun May 6 03:17:42 2018 From: gershomb at gmail.com (Gershom B) Date: Sat, 5 May 2018 23:17:42 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: On May 5, 2018 at 10:43:57 PM, David Feuer (david.feuer at gmail.com) wrote: Your law doesn't blow up for infinite structures (your care wasn't for nothing) but it doesn't say very much about them. No, I’m pretty sure that the two formulations say exactly the same thing in this case. I do think that your formulation is more elegant and if that helps the committee along to a decision, as I said, I’m more than happy if they go with it. I just want to be sufficiently clear on what is being said by either formulation. And if you do have a good example where they differ on infinite structures, it would be interesting to see. -g -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sun May 6 03:27:16 2018 From: david.feuer at gmail.com (David Feuer) Date: Sun, 06 May 2018 03:27:16 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: I withdraw my statement about infinite structures (I'm not really sure one way or the other). I re-assert my claim about IO. On Sat, May 5, 2018, 11:17 PM Gershom B wrote: > On May 5, 2018 at 10:43:57 PM, David Feuer (david.feuer at gmail.com) wrote: > > Your law doesn't blow up for infinite structures (your care wasn't for > nothing) but it doesn't say very much about them. > > No, I’m pretty sure that the two formulations say exactly the same thing > in this case. I do think that your formulation is more elegant and if that > helps the committee along to a decision, as I said, I’m more than happy if > they go with it. I just want to be sufficiently clear on what is being said > by either formulation. And if you do have a good example where they differ > on infinite structures, it would be interesting to see. > > -g > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sun May 6 04:40:42 2018 From: david.feuer at gmail.com (David Feuer) Date: Sun, 06 May 2018 04:40:42 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Two more points: People have previously considered unusual Foldable instances that this law would prohibit. See for example Petr Pudlák's example instance for Store f a [*]. I don't have a very strong opinion about whether such things should be allowed, but I think it's only fair to mention them. If the Committee chooses to accept the proposal, I suspect it would be reasonable to add that if the type is also a Functor, then it should be possible to write a Traversable instance compatible with the Functor and Foldable instances. This would subsume the current foldMap f = fold . fmap f law. [*] https://stackoverflow.com/a/12896512/1477667 On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: > I actually don't have any real objection to something like David's version > of the law. > > Unlike the GenericSet version, it at first glance feels like it handles > the GADT-based cases without tripping on the cases where the law doesn't > apply because it doesn't just doesn't type check. That had been my major > objection to Gershom's law. > > -Edward > > On Sat, May 5, 2018 at 5:09 PM, David Feuer wrote: > >> I have another idea that might be worth considering. I think it's a lot >> simpler than yours. >> >> Law: If t is a Foldable instance, then there must exist: >> >> 1. A Traversable instance u and >> 2. An injective function >> toTrav :: t a -> u a >> >> Such that >> >> foldMap @t = foldMapDefault . toTrav >> >> I'm pretty sure this gets at the point you're trying to make. >> >> >> On May 3, 2018 11:58 AM, "Gershom B" wrote: >> >> This came up before (see the prior thread): >> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >> >> The thread at that time grew rather large, and only at the end did I >> come up with what I continue to think is a satisfactory formulation of >> the law. >> >> However, at that point nobody really acted to do anything about it. >> >> I would like to _formally request that the core libraries committee >> review_ the final version of the law as proposed, for addition to >> Foldable documentation: >> >> == >> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >> Ord), where GenericSet is otherwise fully abstract: >> >> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >> maybe True (`Foldable.elem` x) (g x) =/= False >> == >> >> The intuition is: "there is no general way to get an `a` out of `f a` >> which cannot be seen by the `Foldable` instance". The use of >> `GenericSet` is to handle the case of GADTs, since even parametric >> polymorphic functions on them may at given _already known_ types have >> specific behaviors. >> >> This law also works over infinite structures. >> >> It rules out "obviously wrong" instances and accepts all the instances >> we want to that I am aware of. >> >> My specific motivation for raising this again is that I am rather >> tired of people saying "well, Foldable has no laws, and it is in base, >> so things without laws are just fine." Foldable does a have a law we >> all know to obey. It just has been rather tricky to state. The above >> provides a decent way to state it. So we should state it. >> >> Cheers, >> Gershom >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gershomb at gmail.com Sun May 6 06:37:09 2018 From: gershomb at gmail.com (Gershom B) Date: Sun, 6 May 2018 02:37:09 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Hmm… I think Pudlák's Store as given in the stackoveflow post is a genuine example of where the two laws differ. That’s unfortunate. The quantification law allows the reasonable instance given in the post. Even with clever use of GADTs I don’t see how to produce a type to fulfill the injectivity law, though I’m not ruling out the possibility altogether. We can cook up something even simpler with the same issue, unfortunately. data Foo a = Foo [Int] (Int -> a) Again, there doesn’t seem to be a way to produce a GADT with an injection that also has traversable. But there is an obvious foldable instance, and it again passes the quantification law. The problem is that injectivity is too strong, but we need to get “almost” there for the law to work. We hit the same problem in fact if we have an `a` in any nontraversable position or structure, even of we have some other ones lying around. So also failing is: data Foo a = Foo [a] (a -> Int). I guess not only is the invectivity law genuinely stronger, it really is _too_ strong. What we want is the “closest thing” to an injection. I sort of know how to say this, but it results in something with the same complicated universal quantification statement (sans GenericSet) that you already dislike in the quantification law. So given  “a GADT `u a` and function `toTrav :: forall a. f a -> u a`” we no longer require `toTrav` to be injective and instead require: `forall (g :: forall a. f a -> Maybe a), exists (h :: forall a. u a -> Maybe a)  such that g === h . toTrav`. In a sense, rather than requiring a global retract, we instead require that each individual “way of getting an `a`” induces a local retract. This is certainly a more complicated condition than “injective”. On the other hand it still avoids the ad-hoc feeling of `GenericSet` that Edward has been concerned about. —Gershom On May 6, 2018 at 12:41:11 AM, David Feuer (david.feuer at gmail.com) wrote: Two more points: People have previously considered unusual Foldable instances that this law would prohibit. See for example Petr Pudlák's example instance for Store f a [*]. I don't have a very strong opinion about whether such things should be allowed, but I think it's only fair to mention them. If the Committee chooses to accept the proposal, I suspect it would be reasonable to add that if the type is also a Functor, then it should be possible to write a Traversable instance compatible with the Functor and Foldable instances. This would subsume the current foldMap f = fold . fmap f law. [*] https://stackoverflow.com/a/12896512/1477667 On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: I actually don't have any real objection to something like David's version of the law.  Unlike the GenericSet version, it at first glance feels like it handles the GADT-based cases without tripping on the cases where the law doesn't apply because it doesn't just doesn't type check. That had been my major objection to Gershom's law. -Edward On Sat, May 5, 2018 at 5:09 PM, David Feuer wrote: I have another idea that might be worth considering. I think it's a lot simpler than yours. Law: If t is a Foldable instance, then there must exist: 1. A Traversable instance u and 2. An injective function        toTrav :: t a -> u a Such that     foldMap @t = foldMapDefault . toTrav I'm pretty sure this gets at the point you're trying to make. On May 3, 2018 11:58 AM, "Gershom B" wrote: This came up before (see the prior thread): https://mail.haskell.org/pipermail/libraries/2015-February/024943.html The thread at that time grew rather large, and only at the end did I come up with what I continue to think is a satisfactory formulation of the law. However, at that point nobody really acted to do anything about it. I would like to _formally request that the core libraries committee review_ the final version of the law as proposed, for addition to Foldable documentation: == Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, Ord), where GenericSet is otherwise fully abstract: forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). maybe True (`Foldable.elem` x) (g x) =/= False == The intuition is: "there is no general way to get an `a` out of `f a` which cannot be seen by the `Foldable` instance". The use of `GenericSet` is to handle the case of GADTs, since even parametric polymorphic functions on them may at given _already known_ types have specific behaviors. This law also works over infinite structures. It rules out "obviously wrong" instances and accepts all the instances we want to that I am aware of. My specific motivation for raising this again is that I am rather tired of people saying "well, Foldable has no laws, and it is in base, so things without laws are just fine." Foldable does a have a law we all know to obey. It just has been rather tricky to state. The above provides a decent way to state it. So we should state it. Cheers, Gershom _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Sun May 6 06:44:03 2018 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Sun, 6 May 2018 08:44:03 +0200 (CEST) Subject: Monoid over reciprocal of reciprocal sum In-Reply-To: <136648cc88d941528d2192abfd9905f@cweb22.nm.nhnsystem.com> References: <136648cc88d941528d2192abfd9905f@cweb22.nm.nhnsystem.com> Message-ID: On Sun, 6 May 2018, 박신환 wrote: > instance Fractional a => Monoid (RecipSum a) where > >     mempty = RecipSum (1 / 0) This would fail for Rational. I'd prefer to simply use Sum monoid on reciprocal values. It also has the advantage that you only need to call 'recip' once after a sequence of (<>). From gershomb at gmail.com Sun May 6 17:56:44 2018 From: gershomb at gmail.com (Gershom B) Date: Sun, 6 May 2018 10:56:44 -0700 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: An amendment to the below, for clarity. There is still a problem, and the fix I suggest is still the fix I suggest. The contravarient example `data Foo a = Foo [a] (a -> Int)` is as I described, and passes quantification and almost-injectivity (as I suggested below), but not strong-injectivity (as proposed by David originally), and is the correct example to necessitate the fix. However, in the other two cases, while indeed they have instances that pass the quantification law (and the almost-injectivity law I suggest), these instances are more subtle than one would imagine. In other words, I wrote that there was an “obvious” foldable instance. But the instances, to pass the laws, are actually somewhat nonobvious. Furthermore, the technique to give these instances can _also_ be used to construct a type that allows them to pass strong-injectivity In particular, these instances are not the ones that come from only feeding the elements of the first component into the projection function of the second component. Rather, they arise from the projection function alone. So for `data Store f a b = Store (f a) (a -> b)`, then we have a Foldable instance for any enumerable type `a` that just foldMaps over every `b` produced by the function as mapped over every `a` in the enumeration, and the first component is discarded. I.e. we view the function as “an a-indexed container of b” and fold over it by knowledge of the index. Similarly for the `data Foo a = Foo [Int] (Int -> a)` case. So, while in general `r -> a` is not traversable, in the case when there is _any_ full enumeration on `r` (i.e., when `r` is known), then it _is_ able to be injected into something traversable, and hence these instances also pass the strong-injectivity law. Note that if there were universal quantification on `Store` then we’d have `Coyoneda` and the instance that _just_ used the `f a` in the first component (as described in Pudlák's SO post) would be the correct one, and furthermore that instance would pass all three versions of the law. Cheers, Gershom On May 6, 2018 at 2:37:12 AM, Gershom B (gershomb at gmail.com) wrote: Hmm… I think Pudlák's Store as given in the stackoveflow post is a genuine example of where the two laws differ. That’s unfortunate. The quantification law allows the reasonable instance given in the post. Even with clever use of GADTs I don’t see how to produce a type to fulfill the injectivity law, though I’m not ruling out the possibility altogether. We can cook up something even simpler with the same issue, unfortunately. data Foo a = Foo [Int] (Int -> a) Again, there doesn’t seem to be a way to produce a GADT with an injection that also has traversable. But there is an obvious foldable instance, and it again passes the quantification law. The problem is that injectivity is too strong, but we need to get “almost” there for the law to work. We hit the same problem in fact if we have an `a` in any nontraversable position or structure, even of we have some other ones lying around. So also failing is: data Foo a = Foo [a] (a -> Int). I guess not only is the invectivity law genuinely stronger, it really is _too_ strong. What we want is the “closest thing” to an injection. I sort of know how to say this, but it results in something with the same complicated universal quantification statement (sans GenericSet) that you already dislike in the quantification law. So given “a GADT `u a` and function `toTrav :: forall a. f a -> u a`” we no longer require `toTrav` to be injective and instead require: `forall (g :: forall a. f a -> Maybe a), exists (h :: forall a. u a -> Maybe a) such that g === h . toTrav`. In a sense, rather than requiring a global retract, we instead require that each individual “way of getting an `a`” induces a local retract. This is certainly a more complicated condition than “injective”. On the other hand it still avoids the ad-hoc feeling of `GenericSet` that Edward has been concerned about. —Gershom On May 6, 2018 at 12:41:11 AM, David Feuer (david.feuer at gmail.com) wrote: Two more points: People have previously considered unusual Foldable instances that this law would prohibit. See for example Petr Pudlák's example instance for Store f a [*]. I don't have a very strong opinion about whether such things should be allowed, but I think it's only fair to mention them. If the Committee chooses to accept the proposal, I suspect it would be reasonable to add that if the type is also a Functor, then it should be possible to write a Traversable instance compatible with the Functor and Foldable instances. This would subsume the current foldMap f = fold . fmap f law. [*] https://stackoverflow.com/a/12896512/1477667 On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: > I actually don't have any real objection to something like David's version > of the law. > > Unlike the GenericSet version, it at first glance feels like it handles > the GADT-based cases without tripping on the cases where the law doesn't > apply because it doesn't just doesn't type check. That had been my major > objection to Gershom's law. > > -Edward > > On Sat, May 5, 2018 at 5:09 PM, David Feuer wrote: > >> I have another idea that might be worth considering. I think it's a lot >> simpler than yours. >> >> Law: If t is a Foldable instance, then there must exist: >> >> 1. A Traversable instance u and >> 2. An injective function >> toTrav :: t a -> u a >> >> Such that >> >> foldMap @t = foldMapDefault . toTrav >> >> I'm pretty sure this gets at the point you're trying to make. >> >> >> On May 3, 2018 11:58 AM, "Gershom B" wrote: >> >> This came up before (see the prior thread): >> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >> >> The thread at that time grew rather large, and only at the end did I >> come up with what I continue to think is a satisfactory formulation of >> the law. >> >> However, at that point nobody really acted to do anything about it. >> >> I would like to _formally request that the core libraries committee >> review_ the final version of the law as proposed, for addition to >> Foldable documentation: >> >> == >> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >> Ord), where GenericSet is otherwise fully abstract: >> >> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >> maybe True (`Foldable.elem` x) (g x) =/= False >> == >> >> The intuition is: "there is no general way to get an `a` out of `f a` >> which cannot be seen by the `Foldable` instance". The use of >> `GenericSet` is to handle the case of GADTs, since even parametric >> polymorphic functions on them may at given _already known_ types have >> specific behaviors. >> >> This law also works over infinite structures. >> >> It rules out "obviously wrong" instances and accepts all the instances >> we want to that I am aware of. >> >> My specific motivation for raising this again is that I am rather >> tired of people saying "well, Foldable has no laws, and it is in base, >> so things without laws are just fine." Foldable does a have a law we >> all know to obey. It just has been rather tricky to state. The above >> provides a decent way to state it. So we should state it. >> >> Cheers, >> Gershom >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sun May 6 19:37:23 2018 From: david.feuer at gmail.com (David Feuer) Date: Sun, 06 May 2018 19:37:23 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: The question, of course, is what we actually want to require. The strong injectivity law prohibits certain instances, yes. But it's not obvious, a priori, that those are "good" instances. Should a Foldable instance be allowed contravariance? Maybe that's just too weird. Nor is it remotely clear to me that the enumeration-based instance you give (that simply ignores the Foldable within) is something we want to accept. If we want Foldable to be as close to Traversable as possible while tolerating types that restrict their arguments in some fashion (i.e., things that look kind of like decorated lists) then I think the strong injectivity law is the way to go. Otherwise we need something else. I don't think your new law is entirely self-explanatory. Perhaps you can break it down a bit? On Sun, May 6, 2018, 1:56 PM Gershom B wrote: > An amendment to the below, for clarity. There is still a problem, and the > fix I suggest is still the fix I suggest. > > The contravarient example `data Foo a = Foo [a] (a -> Int)` is as I > described, and passes quantification and almost-injectivity (as I suggested > below), but not strong-injectivity (as proposed by David originally), and > is the correct example to necessitate the fix. > > However, in the other two cases, while indeed they have instances that > pass the quantification law (and the almost-injectivity law I suggest), > these instances are more subtle than one would imagine. In other words, I > wrote that there was an “obvious” foldable instance. But the instances, to > pass the laws, are actually somewhat nonobvious. Furthermore, the technique > to give these instances can _also_ be used to construct a type that allows > them to pass strong-injectivity > > In particular, these instances are not the ones that come from only > feeding the elements of the first component into the projection function of > the second component. Rather, they arise from the projection function alone. > > So for `data Store f a b = Store (f a) (a -> b)`, then we have a Foldable > instance for any enumerable type `a` that just foldMaps over every `b` > produced by the function as mapped over every `a` in the enumeration, and > the first component is discarded. I.e. we view the function as “an > a-indexed container of b” and fold over it by knowledge of the index. > Similarly for the `data Foo a = Foo [Int] (Int -> a)` case. > > So, while in general `r -> a` is not traversable, in the case when there > is _any_ full enumeration on `r` (i.e., when `r` is known), then it _is_ > able to be injected into something traversable, and hence these instances > also pass the strong-injectivity law. > > Note that if there were universal quantification on `Store` then we’d have > `Coyoneda` and the instance that _just_ used the `f a` in the first > component (as described in Pudlák's SO post) would be the correct one, and > furthermore that instance would pass all three versions of the law. > > Cheers, > Gershom > > > On May 6, 2018 at 2:37:12 AM, Gershom B (gershomb at gmail.com) wrote: > > Hmm… I think Pudlák's Store as given in the stackoveflow post is a genuine > example of where the two laws differ. That’s unfortunate. > > The quantification law allows the reasonable instance given in the post. > Even with clever use of GADTs I don’t see how to produce a type to fulfill > the injectivity law, though I’m not ruling out the possibility altogether. > > We can cook up something even simpler with the same issue, unfortunately. > > data Foo a = Foo [Int] (Int -> a) > > Again, there doesn’t seem to be a way to produce a GADT with an injection > that also has traversable. But there is an obvious foldable instance, and > it again passes the quantification law. > > The problem is that injectivity is too strong, but we need to get “almost” > there for the law to work. We hit the same problem in fact if we have an > `a` in any nontraversable position or structure, even of we have some other > ones lying around. So also failing is: > > data Foo a = Foo [a] (a -> Int). > > I guess not only is the invectivity law genuinely stronger, it really is > _too_ strong. > > What we want is the “closest thing” to an injection. I sort of know how to > say this, but it results in something with the same complicated universal > quantification statement (sans GenericSet) that you already dislike in the > quantification law. > > So given “a GADT `u a` and function `toTrav :: forall a. f a -> u a`” we > no longer require `toTrav` to be injective and instead require: > > `forall (g :: forall a. f a -> Maybe a), exists (h :: forall a. u a -> > Maybe a) such that g === h . toTrav`. > > In a sense, rather than requiring a global retract, we instead require > that each individual “way of getting an `a`” induces a local retract. > > This is certainly a more complicated condition than “injective”. On the > other hand it still avoids the ad-hoc feeling of `GenericSet` that Edward > has been concerned about. > > —Gershom > > > On May 6, 2018 at 12:41:11 AM, David Feuer (david.feuer at gmail.com) wrote: > > Two more points: > > People have previously considered unusual Foldable instances that this law > would prohibit. See for example Petr Pudlák's example instance for Store f > a [*]. I don't have a very strong opinion about whether such things should > be allowed, but I think it's only fair to mention them. > > If the Committee chooses to accept the proposal, I suspect it would be > reasonable to add that if the type is also a Functor, then it should be > possible to write a Traversable instance compatible with the Functor and > Foldable instances. This would subsume the current foldMap f = fold . fmap > f law. > > [*] https://stackoverflow.com/a/12896512/1477667 > > On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: > >> I actually don't have any real objection to something like David's >> version of the law. >> >> Unlike the GenericSet version, it at first glance feels like it handles >> the GADT-based cases without tripping on the cases where the law doesn't >> apply because it doesn't just doesn't type check. That had been my major >> objection to Gershom's law. >> >> -Edward >> >> On Sat, May 5, 2018 at 5:09 PM, David Feuer >> wrote: >> >>> I have another idea that might be worth considering. I think it's a lot >>> simpler than yours. >>> >>> Law: If t is a Foldable instance, then there must exist: >>> >>> 1. A Traversable instance u and >>> 2. An injective function >>> toTrav :: t a -> u a >>> >>> Such that >>> >>> foldMap @t = foldMapDefault . toTrav >>> >>> I'm pretty sure this gets at the point you're trying to make. >>> >>> >>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>> >>> This came up before (see the prior thread): >>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>> >>> The thread at that time grew rather large, and only at the end did I >>> come up with what I continue to think is a satisfactory formulation of >>> the law. >>> >>> However, at that point nobody really acted to do anything about it. >>> >>> I would like to _formally request that the core libraries committee >>> review_ the final version of the law as proposed, for addition to >>> Foldable documentation: >>> >>> == >>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>> Ord), where GenericSet is otherwise fully abstract: >>> >>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>> maybe True (`Foldable.elem` x) (g x) =/= False >>> == >>> >>> The intuition is: "there is no general way to get an `a` out of `f a` >>> which cannot be seen by the `Foldable` instance". The use of >>> `GenericSet` is to handle the case of GADTs, since even parametric >>> polymorphic functions on them may at given _already known_ types have >>> specific behaviors. >>> >>> This law also works over infinite structures. >>> >>> It rules out "obviously wrong" instances and accepts all the instances >>> we want to that I am aware of. >>> >>> My specific motivation for raising this again is that I am rather >>> tired of people saying "well, Foldable has no laws, and it is in base, >>> so things without laws are just fine." Foldable does a have a law we >>> all know to obey. It just has been rather tricky to state. The above >>> provides a decent way to state it. So we should state it. >>> >>> Cheers, >>> Gershom >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> >>> >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> >> _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gershomb at gmail.com Sun May 6 19:47:55 2018 From: gershomb at gmail.com (Gershom B) Date: Sun, 6 May 2018 15:47:55 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: The new law is my attempt to turn the strong-injectivity law into what I thought it was — i.e. a reformulation of the original quantification law. It tries to state the same property —“anything `a` you can get ‘out’ of a foldable `f a` is reachable by folding over it”. The idea is that we don’t want some ad-hoc law about things that are “too weird” or whatever. Rather we want something that states a meaningful universal property that expresses the “meaning” of Foldable — which is that it lets you (univerally) fold over "all the `a` in an `f a`”. Clearly if I have a function `a -> Int`, then that doesn’t in any sense “contain” any `a`, so it makes sense that Foldable just ignores it. This is close to, but not exactly, the same as picking out all the (not-necessarily-strictly-) positive `a`. Cheers, Gershom p.s. You write "Nor is it remotely clear to me that the enumeration-based instance you give… is something we want to accept.” But note that _all_ versions of the laws, including strong-injectivity, accept this instance. It is _only_ in things like the contravariant case where we can observe a difference. On May 6, 2018 at 3:37:53 PM, David Feuer (david.feuer at gmail.com) wrote: The question, of course, is what we actually want to require. The strong injectivity law prohibits certain instances, yes. But it's not obvious, a priori, that those are "good" instances. Should a Foldable instance be allowed contravariance? Maybe that's just too weird. Nor is it remotely clear to me that the enumeration-based instance you give (that simply ignores the Foldable within) is something we want to accept. If we want Foldable to be as close to Traversable as possible while tolerating types that restrict their arguments in some fashion (i.e., things that look kind of like decorated lists) then I think the strong injectivity law is the way to go. Otherwise we need something else. I don't think your new law is entirely self-explanatory. Perhaps you can break it down a bit? On Sun, May 6, 2018, 1:56 PM Gershom B wrote: An amendment to the below, for clarity. There is still a problem, and the fix I suggest is still the fix I suggest. The contravarient example `data Foo a = Foo [a] (a -> Int)` is as I described, and passes quantification and almost-injectivity (as I suggested below), but not strong-injectivity (as proposed by David originally), and is the correct example to necessitate the fix. However, in the other two cases, while indeed they have instances that pass the quantification law (and the almost-injectivity law I suggest), these instances are more subtle than one would imagine. In other words, I wrote that there was an “obvious” foldable instance. But the instances, to pass the laws, are actually somewhat nonobvious. Furthermore, the technique to give these instances can _also_ be used to construct a type that allows them to pass strong-injectivity In particular, these instances are not the ones that come from only feeding the elements of the first component into the projection function of the second component. Rather, they arise from the projection function alone. So for `data Store f a b = Store (f a) (a -> b)`, then we have a Foldable instance for any enumerable type `a` that just foldMaps over every `b` produced by the function as mapped over every `a` in the enumeration, and the first component is discarded. I.e. we view the function as “an a-indexed container of b” and fold over it by knowledge of the index. Similarly for the `data Foo a = Foo [Int] (Int -> a)` case. So, while in general `r -> a` is not traversable, in the case when there is _any_ full enumeration on `r` (i.e., when `r` is known), then it _is_ able to be injected into something traversable, and hence these instances also pass the strong-injectivity law. Note that if there were universal quantification on `Store` then we’d have `Coyoneda` and the instance that _just_ used the `f a` in the first component (as described in Pudlák's SO post) would be the correct one, and furthermore that instance would pass all three versions of the law. Cheers, Gershom On May 6, 2018 at 2:37:12 AM, Gershom B (gershomb at gmail.com) wrote: Hmm… I think Pudlák's Store as given in the stackoveflow post is a genuine example of where the two laws differ. That’s unfortunate. The quantification law allows the reasonable instance given in the post. Even with clever use of GADTs I don’t see how to produce a type to fulfill the injectivity law, though I’m not ruling out the possibility altogether. We can cook up something even simpler with the same issue, unfortunately. data Foo a = Foo [Int] (Int -> a) Again, there doesn’t seem to be a way to produce a GADT with an injection that also has traversable. But there is an obvious foldable instance, and it again passes the quantification law. The problem is that injectivity is too strong, but we need to get “almost” there for the law to work. We hit the same problem in fact if we have an `a` in any nontraversable position or structure, even of we have some other ones lying around. So also failing is: data Foo a = Foo [a] (a -> Int). I guess not only is the invectivity law genuinely stronger, it really is _too_ strong. What we want is the “closest thing” to an injection. I sort of know how to say this, but it results in something with the same complicated universal quantification statement (sans GenericSet) that you already dislike in the quantification law. So given  “a GADT `u a` and function `toTrav :: forall a. f a -> u a`” we no longer require `toTrav` to be injective and instead require: `forall (g :: forall a. f a -> Maybe a), exists (h :: forall a. u a -> Maybe a)  such that g === h . toTrav`. In a sense, rather than requiring a global retract, we instead require that each individual “way of getting an `a`” induces a local retract. This is certainly a more complicated condition than “injective”. On the other hand it still avoids the ad-hoc feeling of `GenericSet` that Edward has been concerned about. —Gershom On May 6, 2018 at 12:41:11 AM, David Feuer (david.feuer at gmail.com) wrote: Two more points: People have previously considered unusual Foldable instances that this law would prohibit. See for example Petr Pudlák's example instance for Store f a [*]. I don't have a very strong opinion about whether such things should be allowed, but I think it's only fair to mention them. If the Committee chooses to accept the proposal, I suspect it would be reasonable to add that if the type is also a Functor, then it should be possible to write a Traversable instance compatible with the Functor and Foldable instances. This would subsume the current foldMap f = fold . fmap f law. [*] https://stackoverflow.com/a/12896512/1477667 On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: I actually don't have any real objection to something like David's version of the law.  Unlike the GenericSet version, it at first glance feels like it handles the GADT-based cases without tripping on the cases where the law doesn't apply because it doesn't just doesn't type check. That had been my major objection to Gershom's law. -Edward On Sat, May 5, 2018 at 5:09 PM, David Feuer wrote: I have another idea that might be worth considering. I think it's a lot simpler than yours. Law: If t is a Foldable instance, then there must exist: 1. A Traversable instance u and 2. An injective function        toTrav :: t a -> u a Such that     foldMap @t = foldMapDefault . toTrav I'm pretty sure this gets at the point you're trying to make. On May 3, 2018 11:58 AM, "Gershom B" wrote: This came up before (see the prior thread): https://mail.haskell.org/pipermail/libraries/2015-February/024943.html The thread at that time grew rather large, and only at the end did I come up with what I continue to think is a satisfactory formulation of the law. However, at that point nobody really acted to do anything about it. I would like to _formally request that the core libraries committee review_ the final version of the law as proposed, for addition to Foldable documentation: == Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, Ord), where GenericSet is otherwise fully abstract: forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). maybe True (`Foldable.elem` x) (g x) =/= False == The intuition is: "there is no general way to get an `a` out of `f a` which cannot be seen by the `Foldable` instance". The use of `GenericSet` is to handle the case of GADTs, since even parametric polymorphic functions on them may at given _already known_ types have specific behaviors. This law also works over infinite structures. It rules out "obviously wrong" instances and accepts all the instances we want to that I am aware of. My specific motivation for raising this again is that I am rather tired of people saying "well, Foldable has no laws, and it is in base, so things without laws are just fine." Foldable does a have a law we all know to obey. It just has been rather tricky to state. The above provides a decent way to state it. So we should state it. Cheers, Gershom _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sun May 6 22:00:58 2018 From: ekmett at gmail.com (Edward Kmett) Date: Sun, 6 May 2018 18:00:58 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: I'm quite in favor of the 'toTrav' flavor of the Foldable law, but I'm pretty strongly against the suggestion that Functor + Foldable must be Traversable. There are reasonable instances that lie in the middle that satisfy the injectivity law and can also be functors. The LZ78 compressed stream stuff that can decompress in any target monoid, the newtype Replicate a = Replicate !Int a for run-length encoding. You can build meaningful Foldable instances for all sorts of graph types that have lots of sharing in them. This law would rule out any Foldable that exploited its nature to improve sharing on the intermediate results. These are in many ways the most interesting and under-exploited points in the Foldable design space. That functionality and the ability to know something about your argument are the two tools offered to you as an author of an instance of Foldable that aren't offered to you with Traversable. fold = foldMap id, states the behavior of fold in terms of foldMap.The other direction defining foldMap in terms of fold and fmap is a free theorem. Hence all of the current interoperability of Foldable and Functor comes for free. No interactions need actually be written as extra laws. But Traversable is not the pushout of the theory of Functor and Traversable. Anything that lies in that middle ground would be needlessly unable to be expressed in exchange for a shiny new "law" that doesn't let you write any new code. I think there is a pretty real distinction between Foldable instances that avoid some of the 'a's like the hinky instance for the Machine type in machines, and ones that can reuse intermediate monoidal results multiple times and gain significant performance dividends for many monoids. The toTrav law at least captures the intuition that "you visit all the 'a's, and rules out the common argument that foldMap _ = mempty is always valid but useless, but adding this law would replace lots of potential O(log n) performance bounds with mandatory O(n) performance bounds, and not offer a single extra line of compiling code to compensate for this loss: Remember you'd have to incur a stronger constraint to actually be able to `traverse` anyways, it can't be written with just the parts of Foldable and Traversable, so nothing is gained and informative cases are definitely lost. (Foldable f, Functor f) is strictly weaker than Traversable f. -Edward On Sun, May 6, 2018 at 12:40 AM, David Feuer wrote: > Two more points: > > People have previously considered unusual Foldable instances that this law > would prohibit. See for example Petr Pudlák's example instance for Store f > a [*]. I don't have a very strong opinion about whether such things should > be allowed, but I think it's only fair to mention them. > > If the Committee chooses to accept the proposal, I suspect it would be > reasonable to add that if the type is also a Functor, then it should be > possible to write a Traversable instance compatible with the Functor and > Foldable instances. This would subsume the current foldMap f = fold . fmap > f law. > > [*] https://stackoverflow.com/a/12896512/1477667 > > On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: > >> I actually don't have any real objection to something like David's >> version of the law. >> >> Unlike the GenericSet version, it at first glance feels like it handles >> the GADT-based cases without tripping on the cases where the law doesn't >> apply because it doesn't just doesn't type check. That had been my major >> objection to Gershom's law. >> >> -Edward >> >> On Sat, May 5, 2018 at 5:09 PM, David Feuer >> wrote: >> >>> I have another idea that might be worth considering. I think it's a lot >>> simpler than yours. >>> >>> Law: If t is a Foldable instance, then there must exist: >>> >>> 1. A Traversable instance u and >>> 2. An injective function >>> toTrav :: t a -> u a >>> >>> Such that >>> >>> foldMap @t = foldMapDefault . toTrav >>> >>> I'm pretty sure this gets at the point you're trying to make. >>> >>> >>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>> >>> This came up before (see the prior thread): >>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>> >>> The thread at that time grew rather large, and only at the end did I >>> come up with what I continue to think is a satisfactory formulation of >>> the law. >>> >>> However, at that point nobody really acted to do anything about it. >>> >>> I would like to _formally request that the core libraries committee >>> review_ the final version of the law as proposed, for addition to >>> Foldable documentation: >>> >>> == >>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>> Ord), where GenericSet is otherwise fully abstract: >>> >>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>> maybe True (`Foldable.elem` x) (g x) =/= False >>> == >>> >>> The intuition is: "there is no general way to get an `a` out of `f a` >>> which cannot be seen by the `Foldable` instance". The use of >>> `GenericSet` is to handle the case of GADTs, since even parametric >>> polymorphic functions on them may at given _already known_ types have >>> specific behaviors. >>> >>> This law also works over infinite structures. >>> >>> It rules out "obviously wrong" instances and accepts all the instances >>> we want to that I am aware of. >>> >>> My specific motivation for raising this again is that I am rather >>> tired of people saying "well, Foldable has no laws, and it is in base, >>> so things without laws are just fine." Foldable does a have a law we >>> all know to obey. It just has been rather tricky to state. The above >>> provides a decent way to state it. So we should state it. >>> >>> Cheers, >>> Gershom >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> >>> >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sun May 6 22:04:34 2018 From: ekmett at gmail.com (Edward Kmett) Date: Sun, 6 May 2018 18:04:34 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: You can get stuck with contravariance in some fashion on the backswing, though, just from holding onto instance constraints about the type 'a'. e.g. If your Foldable data type captures a Num instance for 'a', it could build fresh 'a's out of the ones you have lying around. There isn't a huge difference between that and just capturing the member of Num that you use. -Edward On Sun, May 6, 2018 at 3:37 PM, David Feuer wrote: > The question, of course, is what we actually want to require. The strong > injectivity law prohibits certain instances, yes. But it's not obvious, a > priori, that those are "good" instances. Should a Foldable instance be > allowed contravariance? Maybe that's just too weird. Nor is it remotely > clear to me that the enumeration-based instance you give (that simply > ignores the Foldable within) is something we want to accept. If we want > Foldable to be as close to Traversable as possible while tolerating types > that restrict their arguments in some fashion (i.e., things that look kind > of like decorated lists) then I think the strong injectivity law is the way > to go. Otherwise we need something else. I don't think your new law is > entirely self-explanatory. Perhaps you can break it down a bit? > > On Sun, May 6, 2018, 1:56 PM Gershom B wrote: > >> An amendment to the below, for clarity. There is still a problem, and the >> fix I suggest is still the fix I suggest. >> >> The contravarient example `data Foo a = Foo [a] (a -> Int)` is as I >> described, and passes quantification and almost-injectivity (as I suggested >> below), but not strong-injectivity (as proposed by David originally), and >> is the correct example to necessitate the fix. >> >> However, in the other two cases, while indeed they have instances that >> pass the quantification law (and the almost-injectivity law I suggest), >> these instances are more subtle than one would imagine. In other words, I >> wrote that there was an “obvious” foldable instance. But the instances, to >> pass the laws, are actually somewhat nonobvious. Furthermore, the technique >> to give these instances can _also_ be used to construct a type that allows >> them to pass strong-injectivity >> >> In particular, these instances are not the ones that come from only >> feeding the elements of the first component into the projection function of >> the second component. Rather, they arise from the projection function alone. >> >> So for `data Store f a b = Store (f a) (a -> b)`, then we have a Foldable >> instance for any enumerable type `a` that just foldMaps over every `b` >> produced by the function as mapped over every `a` in the enumeration, and >> the first component is discarded. I.e. we view the function as “an >> a-indexed container of b” and fold over it by knowledge of the index. >> Similarly for the `data Foo a = Foo [Int] (Int -> a)` case. >> >> So, while in general `r -> a` is not traversable, in the case when there >> is _any_ full enumeration on `r` (i.e., when `r` is known), then it _is_ >> able to be injected into something traversable, and hence these instances >> also pass the strong-injectivity law. >> >> Note that if there were universal quantification on `Store` then we’d >> have `Coyoneda` and the instance that _just_ used the `f a` in the first >> component (as described in Pudlák's SO post) would be the correct one, and >> furthermore that instance would pass all three versions of the law. >> >> Cheers, >> Gershom >> >> >> On May 6, 2018 at 2:37:12 AM, Gershom B (gershomb at gmail.com) wrote: >> >> Hmm… I think Pudlák's Store as given in the stackoveflow post is a >> genuine example of where the two laws differ. That’s unfortunate. >> >> The quantification law allows the reasonable instance given in the post. >> Even with clever use of GADTs I don’t see how to produce a type to fulfill >> the injectivity law, though I’m not ruling out the possibility altogether. >> >> We can cook up something even simpler with the same issue, unfortunately. >> >> data Foo a = Foo [Int] (Int -> a) >> >> Again, there doesn’t seem to be a way to produce a GADT with an injection >> that also has traversable. But there is an obvious foldable instance, and >> it again passes the quantification law. >> >> The problem is that injectivity is too strong, but we need to get >> “almost” there for the law to work. We hit the same problem in fact if we >> have an `a` in any nontraversable position or structure, even of we have >> some other ones lying around. So also failing is: >> >> data Foo a = Foo [a] (a -> Int). >> >> I guess not only is the invectivity law genuinely stronger, it really is >> _too_ strong. >> >> What we want is the “closest thing” to an injection. I sort of know how >> to say this, but it results in something with the same complicated >> universal quantification statement (sans GenericSet) that you already >> dislike in the quantification law. >> >> So given “a GADT `u a` and function `toTrav :: forall a. f a -> u a`” we >> no longer require `toTrav` to be injective and instead require: >> >> `forall (g :: forall a. f a -> Maybe a), exists (h :: forall a. u a -> >> Maybe a) such that g === h . toTrav`. >> >> In a sense, rather than requiring a global retract, we instead require >> that each individual “way of getting an `a`” induces a local retract. >> >> This is certainly a more complicated condition than “injective”. On the >> other hand it still avoids the ad-hoc feeling of `GenericSet` that Edward >> has been concerned about. >> >> —Gershom >> >> >> On May 6, 2018 at 12:41:11 AM, David Feuer (david.feuer at gmail.com) wrote: >> >> Two more points: >> >> People have previously considered unusual Foldable instances that this >> law would prohibit. See for example Petr Pudlák's example instance for >> Store f a [*]. I don't have a very strong opinion about whether such things >> should be allowed, but I think it's only fair to mention them. >> >> If the Committee chooses to accept the proposal, I suspect it would be >> reasonable to add that if the type is also a Functor, then it should be >> possible to write a Traversable instance compatible with the Functor and >> Foldable instances. This would subsume the current foldMap f = fold . fmap >> f law. >> >> [*] https://stackoverflow.com/a/12896512/1477667 >> >> On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: >> >>> I actually don't have any real objection to something like David's >>> version of the law. >>> >>> Unlike the GenericSet version, it at first glance feels like it handles >>> the GADT-based cases without tripping on the cases where the law doesn't >>> apply because it doesn't just doesn't type check. That had been my major >>> objection to Gershom's law. >>> >>> -Edward >>> >>> On Sat, May 5, 2018 at 5:09 PM, David Feuer >>> wrote: >>> >>>> I have another idea that might be worth considering. I think it's a lot >>>> simpler than yours. >>>> >>>> Law: If t is a Foldable instance, then there must exist: >>>> >>>> 1. A Traversable instance u and >>>> 2. An injective function >>>> toTrav :: t a -> u a >>>> >>>> Such that >>>> >>>> foldMap @t = foldMapDefault . toTrav >>>> >>>> I'm pretty sure this gets at the point you're trying to make. >>>> >>>> >>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>> >>>> This came up before (see the prior thread): >>>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>>> >>>> The thread at that time grew rather large, and only at the end did I >>>> come up with what I continue to think is a satisfactory formulation of >>>> the law. >>>> >>>> However, at that point nobody really acted to do anything about it. >>>> >>>> I would like to _formally request that the core libraries committee >>>> review_ the final version of the law as proposed, for addition to >>>> Foldable documentation: >>>> >>>> == >>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>> Ord), where GenericSet is otherwise fully abstract: >>>> >>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>> == >>>> >>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>> which cannot be seen by the `Foldable` instance". The use of >>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>> polymorphic functions on them may at given _already known_ types have >>>> specific behaviors. >>>> >>>> This law also works over infinite structures. >>>> >>>> It rules out "obviously wrong" instances and accepts all the instances >>>> we want to that I am aware of. >>>> >>>> My specific motivation for raising this again is that I am rather >>>> tired of people saying "well, Foldable has no laws, and it is in base, >>>> so things without laws are just fine." Foldable does a have a law we >>>> all know to obey. It just has been rather tricky to state. The above >>>> provides a decent way to state it. So we should state it. >>>> >>>> Cheers, >>>> Gershom >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >>>> >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >>> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sun May 6 22:40:10 2018 From: david.feuer at gmail.com (David Feuer) Date: Sun, 06 May 2018 22:40:10 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: No objection to leaving that out if it's a problem, but I'm curious about the details of your example. On Sun, May 6, 2018, 6:01 PM Edward Kmett wrote: > I'm quite in favor of the 'toTrav' flavor of the Foldable law, but I'm > pretty strongly against the suggestion that Functor + Foldable must be > Traversable. > > There are reasonable instances that lie in the middle that satisfy the > injectivity law and can also be functors. The LZ78 compressed stream stuff > that can decompress in any target monoid, the newtype Replicate a = > Replicate !Int a for run-length encoding. You can build meaningful Foldable > instances for all sorts of graph types that have lots of sharing in them. > This law would rule out any Foldable that exploited its nature to improve > sharing on the intermediate results. These are in many ways the most > interesting and under-exploited points in the Foldable design space. That > functionality and the ability to know something about your argument are the > two tools offered to you as an author of an instance of Foldable that > aren't offered to you with Traversable. > > fold = foldMap id, states the behavior of fold in terms of foldMap.The > other direction defining foldMap in terms of fold and fmap is a free > theorem. Hence all of the current interoperability of Foldable and Functor > comes for free. No interactions need actually be written as extra laws. > > But Traversable is not the pushout of the theory of Functor and > Traversable. Anything that lies in that middle ground would be needlessly > unable to be expressed in exchange for a shiny new "law" that doesn't let > you write any new code. I think there is a pretty real distinction between > Foldable instances that avoid some of the 'a's like the hinky instance for > the Machine type in machines, and ones that can reuse intermediate monoidal > results multiple times and gain significant performance dividends for many > monoids. > > The toTrav law at least captures the intuition that "you visit all the > 'a's, and rules out the common argument that foldMap _ = mempty is always > valid but useless, but adding this law would replace lots of potential > O(log n) performance bounds with mandatory O(n) performance bounds, and not > offer a single extra line of compiling code to compensate for this loss: > Remember you'd have to incur a stronger constraint to actually be able to > `traverse` anyways, it can't be written with just the parts of Foldable and > Traversable, so nothing is gained and informative cases are definitely lost. > > (Foldable f, Functor f) is strictly weaker than Traversable f. > > -Edward > > On Sun, May 6, 2018 at 12:40 AM, David Feuer > wrote: > >> Two more points: >> >> People have previously considered unusual Foldable instances that this >> law would prohibit. See for example Petr Pudlák's example instance for >> Store f a [*]. I don't have a very strong opinion about whether such things >> should be allowed, but I think it's only fair to mention them. >> >> If the Committee chooses to accept the proposal, I suspect it would be >> reasonable to add that if the type is also a Functor, then it should be >> possible to write a Traversable instance compatible with the Functor and >> Foldable instances. This would subsume the current foldMap f = fold . fmap >> f law. >> >> [*] https://stackoverflow.com/a/12896512/1477667 >> >> On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: >> >>> I actually don't have any real objection to something like David's >>> version of the law. >>> >>> Unlike the GenericSet version, it at first glance feels like it handles >>> the GADT-based cases without tripping on the cases where the law doesn't >>> apply because it doesn't just doesn't type check. That had been my major >>> objection to Gershom's law. >>> >>> -Edward >>> >>> On Sat, May 5, 2018 at 5:09 PM, David Feuer >>> wrote: >>> >>>> I have another idea that might be worth considering. I think it's a lot >>>> simpler than yours. >>>> >>>> Law: If t is a Foldable instance, then there must exist: >>>> >>>> 1. A Traversable instance u and >>>> 2. An injective function >>>> toTrav :: t a -> u a >>>> >>>> Such that >>>> >>>> foldMap @t = foldMapDefault . toTrav >>>> >>>> I'm pretty sure this gets at the point you're trying to make. >>>> >>>> >>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>> >>>> This came up before (see the prior thread): >>>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>>> >>>> The thread at that time grew rather large, and only at the end did I >>>> come up with what I continue to think is a satisfactory formulation of >>>> the law. >>>> >>>> However, at that point nobody really acted to do anything about it. >>>> >>>> I would like to _formally request that the core libraries committee >>>> review_ the final version of the law as proposed, for addition to >>>> Foldable documentation: >>>> >>>> == >>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>> Ord), where GenericSet is otherwise fully abstract: >>>> >>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>> == >>>> >>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>> which cannot be seen by the `Foldable` instance". The use of >>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>> polymorphic functions on them may at given _already known_ types have >>>> specific behaviors. >>>> >>>> This law also works over infinite structures. >>>> >>>> It rules out "obviously wrong" instances and accepts all the instances >>>> we want to that I am aware of. >>>> >>>> My specific motivation for raising this again is that I am rather >>>> tired of people saying "well, Foldable has no laws, and it is in base, >>>> so things without laws are just fine." Foldable does a have a law we >>>> all know to obey. It just has been rather tricky to state. The above >>>> provides a decent way to state it. So we should state it. >>>> >>>> Cheers, >>>> Gershom >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >>>> >>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >>> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Sun May 6 23:28:40 2018 From: david.feuer at gmail.com (David Feuer) Date: Sun, 06 May 2018 23:28:40 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: I don't understand. Something like data Foo a where Foo :: Num a => a -> Foo a has a perfectly good "forgetful" injection: toTrav (Foo a) = Identity a This is injective because of class coherence. On Sun, May 6, 2018, 6:04 PM Edward Kmett wrote: > You can get stuck with contravariance in some fashion on the backswing, > though, just from holding onto instance constraints about the type 'a'. > e.g. If your Foldable data type captures a Num instance for 'a', it could > build fresh 'a's out of the ones you have lying around. > > There isn't a huge difference between that and just capturing the member > of Num that you use. > > -Edward > > On Sun, May 6, 2018 at 3:37 PM, David Feuer wrote: > >> The question, of course, is what we actually want to require. The strong >> injectivity law prohibits certain instances, yes. But it's not obvious, a >> priori, that those are "good" instances. Should a Foldable instance be >> allowed contravariance? Maybe that's just too weird. Nor is it remotely >> clear to me that the enumeration-based instance you give (that simply >> ignores the Foldable within) is something we want to accept. If we want >> Foldable to be as close to Traversable as possible while tolerating types >> that restrict their arguments in some fashion (i.e., things that look kind >> of like decorated lists) then I think the strong injectivity law is the way >> to go. Otherwise we need something else. I don't think your new law is >> entirely self-explanatory. Perhaps you can break it down a bit? >> >> On Sun, May 6, 2018, 1:56 PM Gershom B wrote: >> >>> An amendment to the below, for clarity. There is still a problem, and >>> the fix I suggest is still the fix I suggest. >>> >>> The contravarient example `data Foo a = Foo [a] (a -> Int)` is as I >>> described, and passes quantification and almost-injectivity (as I suggested >>> below), but not strong-injectivity (as proposed by David originally), and >>> is the correct example to necessitate the fix. >>> >>> However, in the other two cases, while indeed they have instances that >>> pass the quantification law (and the almost-injectivity law I suggest), >>> these instances are more subtle than one would imagine. In other words, I >>> wrote that there was an “obvious” foldable instance. But the instances, to >>> pass the laws, are actually somewhat nonobvious. Furthermore, the technique >>> to give these instances can _also_ be used to construct a type that allows >>> them to pass strong-injectivity >>> >>> In particular, these instances are not the ones that come from only >>> feeding the elements of the first component into the projection function of >>> the second component. Rather, they arise from the projection function alone. >>> >>> So for `data Store f a b = Store (f a) (a -> b)`, then we have a >>> Foldable instance for any enumerable type `a` that just foldMaps over every >>> `b` produced by the function as mapped over every `a` in the enumeration, >>> and the first component is discarded. I.e. we view the function as “an >>> a-indexed container of b” and fold over it by knowledge of the index. >>> Similarly for the `data Foo a = Foo [Int] (Int -> a)` case. >>> >>> So, while in general `r -> a` is not traversable, in the case when there >>> is _any_ full enumeration on `r` (i.e., when `r` is known), then it _is_ >>> able to be injected into something traversable, and hence these instances >>> also pass the strong-injectivity law. >>> >>> Note that if there were universal quantification on `Store` then we’d >>> have `Coyoneda` and the instance that _just_ used the `f a` in the first >>> component (as described in Pudlák's SO post) would be the correct one, and >>> furthermore that instance would pass all three versions of the law. >>> >>> Cheers, >>> Gershom >>> >>> >>> On May 6, 2018 at 2:37:12 AM, Gershom B (gershomb at gmail.com) wrote: >>> >>> Hmm… I think Pudlák's Store as given in the stackoveflow post is a >>> genuine example of where the two laws differ. That’s unfortunate. >>> >>> The quantification law allows the reasonable instance given in the post. >>> Even with clever use of GADTs I don’t see how to produce a type to fulfill >>> the injectivity law, though I’m not ruling out the possibility altogether. >>> >>> We can cook up something even simpler with the same issue, unfortunately. >>> >>> data Foo a = Foo [Int] (Int -> a) >>> >>> Again, there doesn’t seem to be a way to produce a GADT with an >>> injection that also has traversable. But there is an obvious foldable >>> instance, and it again passes the quantification law. >>> >>> The problem is that injectivity is too strong, but we need to get >>> “almost” there for the law to work. We hit the same problem in fact if we >>> have an `a` in any nontraversable position or structure, even of we have >>> some other ones lying around. So also failing is: >>> >>> data Foo a = Foo [a] (a -> Int). >>> >>> I guess not only is the invectivity law genuinely stronger, it really is >>> _too_ strong. >>> >>> What we want is the “closest thing” to an injection. I sort of know how >>> to say this, but it results in something with the same complicated >>> universal quantification statement (sans GenericSet) that you already >>> dislike in the quantification law. >>> >>> So given “a GADT `u a` and function `toTrav :: forall a. f a -> u a`” >>> we no longer require `toTrav` to be injective and instead require: >>> >>> `forall (g :: forall a. f a -> Maybe a), exists (h :: forall a. u a -> >>> Maybe a) such that g === h . toTrav`. >>> >>> In a sense, rather than requiring a global retract, we instead require >>> that each individual “way of getting an `a`” induces a local retract. >>> >>> This is certainly a more complicated condition than “injective”. On the >>> other hand it still avoids the ad-hoc feeling of `GenericSet` that Edward >>> has been concerned about. >>> >>> —Gershom >>> >>> >>> On May 6, 2018 at 12:41:11 AM, David Feuer (david.feuer at gmail.com) >>> wrote: >>> >>> Two more points: >>> >>> People have previously considered unusual Foldable instances that this >>> law would prohibit. See for example Petr Pudlák's example instance for >>> Store f a [*]. I don't have a very strong opinion about whether such things >>> should be allowed, but I think it's only fair to mention them. >>> >>> If the Committee chooses to accept the proposal, I suspect it would be >>> reasonable to add that if the type is also a Functor, then it should be >>> possible to write a Traversable instance compatible with the Functor and >>> Foldable instances. This would subsume the current foldMap f = fold . fmap >>> f law. >>> >>> [*] https://stackoverflow.com/a/12896512/1477667 >>> >>> On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: >>> >>>> I actually don't have any real objection to something like David's >>>> version of the law. >>>> >>>> Unlike the GenericSet version, it at first glance feels like it handles >>>> the GADT-based cases without tripping on the cases where the law doesn't >>>> apply because it doesn't just doesn't type check. That had been my major >>>> objection to Gershom's law. >>>> >>>> -Edward >>>> >>>> On Sat, May 5, 2018 at 5:09 PM, David Feuer >>>> wrote: >>>> >>>>> I have another idea that might be worth considering. I think it's a >>>>> lot simpler than yours. >>>>> >>>>> Law: If t is a Foldable instance, then there must exist: >>>>> >>>>> 1. A Traversable instance u and >>>>> 2. An injective function >>>>> toTrav :: t a -> u a >>>>> >>>>> Such that >>>>> >>>>> foldMap @t = foldMapDefault . toTrav >>>>> >>>>> I'm pretty sure this gets at the point you're trying to make. >>>>> >>>>> >>>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>>> >>>>> This came up before (see the prior thread): >>>>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>>>> >>>>> The thread at that time grew rather large, and only at the end did I >>>>> come up with what I continue to think is a satisfactory formulation of >>>>> the law. >>>>> >>>>> However, at that point nobody really acted to do anything about it. >>>>> >>>>> I would like to _formally request that the core libraries committee >>>>> review_ the final version of the law as proposed, for addition to >>>>> Foldable documentation: >>>>> >>>>> == >>>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>>> Ord), where GenericSet is otherwise fully abstract: >>>>> >>>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>>> == >>>>> >>>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>>> which cannot be seen by the `Foldable` instance". The use of >>>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>>> polymorphic functions on them may at given _already known_ types have >>>>> specific behaviors. >>>>> >>>>> This law also works over infinite structures. >>>>> >>>>> It rules out "obviously wrong" instances and accepts all the instances >>>>> we want to that I am aware of. >>>>> >>>>> My specific motivation for raising this again is that I am rather >>>>> tired of people saying "well, Foldable has no laws, and it is in base, >>>>> so things without laws are just fine." Foldable does a have a law we >>>>> all know to obey. It just has been rather tricky to state. The above >>>>> provides a decent way to state it. So we should state it. >>>>> >>>>> Cheers, >>>>> Gershom >>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>>>> >>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >>> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Sun May 6 23:39:36 2018 From: ekmett at gmail.com (Edward Kmett) Date: Sun, 6 May 2018 19:39:36 -0400 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Fair point. I was more thinking about the fact that you don't necessarily visit all of the a's because you can use the combinators you have there to generate an unbounded number of combination of them than the injectivity concern. On Sun, May 6, 2018 at 7:28 PM, David Feuer wrote: > I don't understand. Something like > > data Foo a where > Foo :: Num a => a -> Foo a > > has a perfectly good "forgetful" injection: > > toTrav (Foo a) = Identity a > > This is injective because of class coherence. > > On Sun, May 6, 2018, 6:04 PM Edward Kmett wrote: > >> You can get stuck with contravariance in some fashion on the backswing, >> though, just from holding onto instance constraints about the type 'a'. >> e.g. If your Foldable data type captures a Num instance for 'a', it could >> build fresh 'a's out of the ones you have lying around. >> >> There isn't a huge difference between that and just capturing the member >> of Num that you use. >> >> -Edward >> >> On Sun, May 6, 2018 at 3:37 PM, David Feuer >> wrote: >> >>> The question, of course, is what we actually want to require. The strong >>> injectivity law prohibits certain instances, yes. But it's not obvious, a >>> priori, that those are "good" instances. Should a Foldable instance be >>> allowed contravariance? Maybe that's just too weird. Nor is it remotely >>> clear to me that the enumeration-based instance you give (that simply >>> ignores the Foldable within) is something we want to accept. If we want >>> Foldable to be as close to Traversable as possible while tolerating types >>> that restrict their arguments in some fashion (i.e., things that look kind >>> of like decorated lists) then I think the strong injectivity law is the way >>> to go. Otherwise we need something else. I don't think your new law is >>> entirely self-explanatory. Perhaps you can break it down a bit? >>> >>> On Sun, May 6, 2018, 1:56 PM Gershom B wrote: >>> >>>> An amendment to the below, for clarity. There is still a problem, and >>>> the fix I suggest is still the fix I suggest. >>>> >>>> The contravarient example `data Foo a = Foo [a] (a -> Int)` is as I >>>> described, and passes quantification and almost-injectivity (as I suggested >>>> below), but not strong-injectivity (as proposed by David originally), and >>>> is the correct example to necessitate the fix. >>>> >>>> However, in the other two cases, while indeed they have instances that >>>> pass the quantification law (and the almost-injectivity law I suggest), >>>> these instances are more subtle than one would imagine. In other words, I >>>> wrote that there was an “obvious” foldable instance. But the instances, to >>>> pass the laws, are actually somewhat nonobvious. Furthermore, the technique >>>> to give these instances can _also_ be used to construct a type that allows >>>> them to pass strong-injectivity >>>> >>>> In particular, these instances are not the ones that come from only >>>> feeding the elements of the first component into the projection function of >>>> the second component. Rather, they arise from the projection function alone. >>>> >>>> So for `data Store f a b = Store (f a) (a -> b)`, then we have a >>>> Foldable instance for any enumerable type `a` that just foldMaps over every >>>> `b` produced by the function as mapped over every `a` in the enumeration, >>>> and the first component is discarded. I.e. we view the function as “an >>>> a-indexed container of b” and fold over it by knowledge of the index. >>>> Similarly for the `data Foo a = Foo [Int] (Int -> a)` case. >>>> >>>> So, while in general `r -> a` is not traversable, in the case when >>>> there is _any_ full enumeration on `r` (i.e., when `r` is known), then it >>>> _is_ able to be injected into something traversable, and hence these >>>> instances also pass the strong-injectivity law. >>>> >>>> Note that if there were universal quantification on `Store` then we’d >>>> have `Coyoneda` and the instance that _just_ used the `f a` in the first >>>> component (as described in Pudlák's SO post) would be the correct one, and >>>> furthermore that instance would pass all three versions of the law. >>>> >>>> Cheers, >>>> Gershom >>>> >>>> >>>> On May 6, 2018 at 2:37:12 AM, Gershom B (gershomb at gmail.com) wrote: >>>> >>>> Hmm… I think Pudlák's Store as given in the stackoveflow post is a >>>> genuine example of where the two laws differ. That’s unfortunate. >>>> >>>> The quantification law allows the reasonable instance given in the >>>> post. Even with clever use of GADTs I don’t see how to produce a type to >>>> fulfill the injectivity law, though I’m not ruling out the possibility >>>> altogether. >>>> >>>> We can cook up something even simpler with the same issue, >>>> unfortunately. >>>> >>>> data Foo a = Foo [Int] (Int -> a) >>>> >>>> Again, there doesn’t seem to be a way to produce a GADT with an >>>> injection that also has traversable. But there is an obvious foldable >>>> instance, and it again passes the quantification law. >>>> >>>> The problem is that injectivity is too strong, but we need to get >>>> “almost” there for the law to work. We hit the same problem in fact if we >>>> have an `a` in any nontraversable position or structure, even of we have >>>> some other ones lying around. So also failing is: >>>> >>>> data Foo a = Foo [a] (a -> Int). >>>> >>>> I guess not only is the invectivity law genuinely stronger, it really >>>> is _too_ strong. >>>> >>>> What we want is the “closest thing” to an injection. I sort of know how >>>> to say this, but it results in something with the same complicated >>>> universal quantification statement (sans GenericSet) that you already >>>> dislike in the quantification law. >>>> >>>> So given “a GADT `u a` and function `toTrav :: forall a. f a -> u a`” >>>> we no longer require `toTrav` to be injective and instead require: >>>> >>>> `forall (g :: forall a. f a -> Maybe a), exists (h :: forall a. u a -> >>>> Maybe a) such that g === h . toTrav`. >>>> >>>> In a sense, rather than requiring a global retract, we instead require >>>> that each individual “way of getting an `a`” induces a local retract. >>>> >>>> This is certainly a more complicated condition than “injective”. On the >>>> other hand it still avoids the ad-hoc feeling of `GenericSet` that Edward >>>> has been concerned about. >>>> >>>> —Gershom >>>> >>>> >>>> On May 6, 2018 at 12:41:11 AM, David Feuer (david.feuer at gmail.com) >>>> wrote: >>>> >>>> Two more points: >>>> >>>> People have previously considered unusual Foldable instances that this >>>> law would prohibit. See for example Petr Pudlák's example instance for >>>> Store f a [*]. I don't have a very strong opinion about whether such things >>>> should be allowed, but I think it's only fair to mention them. >>>> >>>> If the Committee chooses to accept the proposal, I suspect it would be >>>> reasonable to add that if the type is also a Functor, then it should be >>>> possible to write a Traversable instance compatible with the Functor and >>>> Foldable instances. This would subsume the current foldMap f = fold . fmap >>>> f law. >>>> >>>> [*] https://stackoverflow.com/a/12896512/1477667 >>>> >>>> On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: >>>> >>>>> I actually don't have any real objection to something like David's >>>>> version of the law. >>>>> >>>>> Unlike the GenericSet version, it at first glance feels like it >>>>> handles the GADT-based cases without tripping on the cases where the law >>>>> doesn't apply because it doesn't just doesn't type check. That had been my >>>>> major objection to Gershom's law. >>>>> >>>>> -Edward >>>>> >>>>> On Sat, May 5, 2018 at 5:09 PM, David Feuer >>>>> wrote: >>>>> >>>>>> I have another idea that might be worth considering. I think it's a >>>>>> lot simpler than yours. >>>>>> >>>>>> Law: If t is a Foldable instance, then there must exist: >>>>>> >>>>>> 1. A Traversable instance u and >>>>>> 2. An injective function >>>>>> toTrav :: t a -> u a >>>>>> >>>>>> Such that >>>>>> >>>>>> foldMap @t = foldMapDefault . toTrav >>>>>> >>>>>> I'm pretty sure this gets at the point you're trying to make. >>>>>> >>>>>> >>>>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>>>> >>>>>> This came up before (see the prior thread): >>>>>> https://mail.haskell.org/pipermail/libraries/2015- >>>>>> February/024943.html >>>>>> >>>>>> The thread at that time grew rather large, and only at the end did I >>>>>> come up with what I continue to think is a satisfactory formulation of >>>>>> the law. >>>>>> >>>>>> However, at that point nobody really acted to do anything about it. >>>>>> >>>>>> I would like to _formally request that the core libraries committee >>>>>> review_ the final version of the law as proposed, for addition to >>>>>> Foldable documentation: >>>>>> >>>>>> == >>>>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>>>> Ord), where GenericSet is otherwise fully abstract: >>>>>> >>>>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>>>> == >>>>>> >>>>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>>>> which cannot be seen by the `Foldable` instance". The use of >>>>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>>>> polymorphic functions on them may at given _already known_ types have >>>>>> specific behaviors. >>>>>> >>>>>> This law also works over infinite structures. >>>>>> >>>>>> It rules out "obviously wrong" instances and accepts all the instances >>>>>> we want to that I am aware of. >>>>>> >>>>>> My specific motivation for raising this again is that I am rather >>>>>> tired of people saying "well, Foldable has no laws, and it is in base, >>>>>> so things without laws are just fine." Foldable does a have a law we >>>>>> all know to obey. It just has been rather tricky to state. The above >>>>>> provides a decent way to state it. So we should state it. >>>>>> >>>>>> Cheers, >>>>>> Gershom >>>>>> _______________________________________________ >>>>>> Libraries mailing list >>>>>> Libraries at haskell.org >>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> >>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> Libraries mailing list >>>>>> Libraries at haskell.org >>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>> >>>>>> >>>>> _______________________________________________ >>>> Libraries mailing list >>>> Libraries at haskell.org >>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>> >>>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Mon May 7 00:52:52 2018 From: david.feuer at gmail.com (David Feuer) Date: Mon, 07 May 2018 00:52:52 +0000 Subject: Proposal: add a foldable law In-Reply-To: References: Message-ID: Still not sure I understand what you mean. The injectivity condition makes it hard to ignore almost anything (unless it's hidden by an abstraction barrier, existential type, etc.). I don't think Num is strong enough for funny business. Integral is, though: data Bar a where Bar :: Integral a => a -> Bar a instance Foldable Bar where foldMap _ _ = mempty type Trav Bar = Const Integer toTrav (Bar a) = Const (toInteger a) On Sun, May 6, 2018, 7:39 PM Edward Kmett wrote: > Fair point. I was more thinking about the fact that you don't necessarily > visit all of the a's because you can use the combinators you have there to > generate an unbounded number of combination of them than the injectivity > concern. > > On Sun, May 6, 2018 at 7:28 PM, David Feuer wrote: > >> I don't understand. Something like >> >> data Foo a where >> Foo :: Num a => a -> Foo a >> >> has a perfectly good "forgetful" injection: >> >> toTrav (Foo a) = Identity a >> >> This is injective because of class coherence. >> >> On Sun, May 6, 2018, 6:04 PM Edward Kmett wrote: >> >>> You can get stuck with contravariance in some fashion on the backswing, >>> though, just from holding onto instance constraints about the type 'a'. >>> e.g. If your Foldable data type captures a Num instance for 'a', it could >>> build fresh 'a's out of the ones you have lying around. >>> >>> There isn't a huge difference between that and just capturing the member >>> of Num that you use. >>> >>> -Edward >>> >>> On Sun, May 6, 2018 at 3:37 PM, David Feuer >>> wrote: >>> >>>> The question, of course, is what we actually want to require. The >>>> strong injectivity law prohibits certain instances, yes. But it's not >>>> obvious, a priori, that those are "good" instances. Should a Foldable >>>> instance be allowed contravariance? Maybe that's just too weird. Nor is it >>>> remotely clear to me that the enumeration-based instance you give (that >>>> simply ignores the Foldable within) is something we want to accept. If we >>>> want Foldable to be as close to Traversable as possible while tolerating >>>> types that restrict their arguments in some fashion (i.e., things that look >>>> kind of like decorated lists) then I think the strong injectivity law is >>>> the way to go. Otherwise we need something else. I don't think your new law >>>> is entirely self-explanatory. Perhaps you can break it down a bit? >>>> >>>> On Sun, May 6, 2018, 1:56 PM Gershom B wrote: >>>> >>>>> An amendment to the below, for clarity. There is still a problem, and >>>>> the fix I suggest is still the fix I suggest. >>>>> >>>>> The contravarient example `data Foo a = Foo [a] (a -> Int)` is as I >>>>> described, and passes quantification and almost-injectivity (as I suggested >>>>> below), but not strong-injectivity (as proposed by David originally), and >>>>> is the correct example to necessitate the fix. >>>>> >>>>> However, in the other two cases, while indeed they have instances that >>>>> pass the quantification law (and the almost-injectivity law I suggest), >>>>> these instances are more subtle than one would imagine. In other words, I >>>>> wrote that there was an “obvious” foldable instance. But the instances, to >>>>> pass the laws, are actually somewhat nonobvious. Furthermore, the technique >>>>> to give these instances can _also_ be used to construct a type that allows >>>>> them to pass strong-injectivity >>>>> >>>>> In particular, these instances are not the ones that come from only >>>>> feeding the elements of the first component into the projection function of >>>>> the second component. Rather, they arise from the projection function alone. >>>>> >>>>> So for `data Store f a b = Store (f a) (a -> b)`, then we have a >>>>> Foldable instance for any enumerable type `a` that just foldMaps over every >>>>> `b` produced by the function as mapped over every `a` in the enumeration, >>>>> and the first component is discarded. I.e. we view the function as “an >>>>> a-indexed container of b” and fold over it by knowledge of the index. >>>>> Similarly for the `data Foo a = Foo [Int] (Int -> a)` case. >>>>> >>>>> So, while in general `r -> a` is not traversable, in the case when >>>>> there is _any_ full enumeration on `r` (i.e., when `r` is known), then it >>>>> _is_ able to be injected into something traversable, and hence these >>>>> instances also pass the strong-injectivity law. >>>>> >>>>> Note that if there were universal quantification on `Store` then we’d >>>>> have `Coyoneda` and the instance that _just_ used the `f a` in the first >>>>> component (as described in Pudlák's SO post) would be the correct one, and >>>>> furthermore that instance would pass all three versions of the law. >>>>> >>>>> Cheers, >>>>> Gershom >>>>> >>>>> >>>>> On May 6, 2018 at 2:37:12 AM, Gershom B (gershomb at gmail.com) wrote: >>>>> >>>>> Hmm… I think Pudlák's Store as given in the stackoveflow post is a >>>>> genuine example of where the two laws differ. That’s unfortunate. >>>>> >>>>> The quantification law allows the reasonable instance given in the >>>>> post. Even with clever use of GADTs I don’t see how to produce a type to >>>>> fulfill the injectivity law, though I’m not ruling out the possibility >>>>> altogether. >>>>> >>>>> We can cook up something even simpler with the same issue, >>>>> unfortunately. >>>>> >>>>> data Foo a = Foo [Int] (Int -> a) >>>>> >>>>> Again, there doesn’t seem to be a way to produce a GADT with an >>>>> injection that also has traversable. But there is an obvious foldable >>>>> instance, and it again passes the quantification law. >>>>> >>>>> The problem is that injectivity is too strong, but we need to get >>>>> “almost” there for the law to work. We hit the same problem in fact if we >>>>> have an `a` in any nontraversable position or structure, even of we have >>>>> some other ones lying around. So also failing is: >>>>> >>>>> data Foo a = Foo [a] (a -> Int). >>>>> >>>>> I guess not only is the invectivity law genuinely stronger, it really >>>>> is _too_ strong. >>>>> >>>>> What we want is the “closest thing” to an injection. I sort of know >>>>> how to say this, but it results in something with the same complicated >>>>> universal quantification statement (sans GenericSet) that you already >>>>> dislike in the quantification law. >>>>> >>>>> So given “a GADT `u a` and function `toTrav :: forall a. f a -> u a`” >>>>> we no longer require `toTrav` to be injective and instead require: >>>>> >>>>> `forall (g :: forall a. f a -> Maybe a), exists (h :: forall a. u a >>>>> -> Maybe a) such that g === h . toTrav`. >>>>> >>>>> In a sense, rather than requiring a global retract, we instead require >>>>> that each individual “way of getting an `a`” induces a local retract. >>>>> >>>>> This is certainly a more complicated condition than “injective”. On >>>>> the other hand it still avoids the ad-hoc feeling of `GenericSet` that >>>>> Edward has been concerned about. >>>>> >>>>> —Gershom >>>>> >>>>> >>>>> On May 6, 2018 at 12:41:11 AM, David Feuer (david.feuer at gmail.com) >>>>> wrote: >>>>> >>>>> Two more points: >>>>> >>>>> People have previously considered unusual Foldable instances that this >>>>> law would prohibit. See for example Petr Pudlák's example instance for >>>>> Store f a [*]. I don't have a very strong opinion about whether such things >>>>> should be allowed, but I think it's only fair to mention them. >>>>> >>>>> If the Committee chooses to accept the proposal, I suspect it would be >>>>> reasonable to add that if the type is also a Functor, then it should be >>>>> possible to write a Traversable instance compatible with the Functor and >>>>> Foldable instances. This would subsume the current foldMap f = fold . fmap >>>>> f law. >>>>> >>>>> [*] https://stackoverflow.com/a/12896512/1477667 >>>>> >>>>> On Sat, May 5, 2018, 10:37 PM Edward Kmett wrote: >>>>> >>>>>> I actually don't have any real objection to something like David's >>>>>> version of the law. >>>>>> >>>>>> Unlike the GenericSet version, it at first glance feels like it >>>>>> handles the GADT-based cases without tripping on the cases where the law >>>>>> doesn't apply because it doesn't just doesn't type check. That had been my >>>>>> major objection to Gershom's law. >>>>>> >>>>>> -Edward >>>>>> >>>>>> On Sat, May 5, 2018 at 5:09 PM, David Feuer >>>>>> wrote: >>>>>> >>>>>>> I have another idea that might be worth considering. I think it's a >>>>>>> lot simpler than yours. >>>>>>> >>>>>>> Law: If t is a Foldable instance, then there must exist: >>>>>>> >>>>>>> 1. A Traversable instance u and >>>>>>> 2. An injective function >>>>>>> toTrav :: t a -> u a >>>>>>> >>>>>>> Such that >>>>>>> >>>>>>> foldMap @t = foldMapDefault . toTrav >>>>>>> >>>>>>> I'm pretty sure this gets at the point you're trying to make. >>>>>>> >>>>>>> >>>>>>> On May 3, 2018 11:58 AM, "Gershom B" wrote: >>>>>>> >>>>>>> This came up before (see the prior thread): >>>>>>> >>>>>>> https://mail.haskell.org/pipermail/libraries/2015-February/024943.html >>>>>>> >>>>>>> The thread at that time grew rather large, and only at the end did I >>>>>>> come up with what I continue to think is a satisfactory formulation >>>>>>> of >>>>>>> the law. >>>>>>> >>>>>>> However, at that point nobody really acted to do anything about it. >>>>>>> >>>>>>> I would like to _formally request that the core libraries committee >>>>>>> review_ the final version of the law as proposed, for addition to >>>>>>> Foldable documentation: >>>>>>> >>>>>>> == >>>>>>> Given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, >>>>>>> Ord), where GenericSet is otherwise fully abstract: >>>>>>> >>>>>>> forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). >>>>>>> maybe True (`Foldable.elem` x) (g x) =/= False >>>>>>> == >>>>>>> >>>>>>> The intuition is: "there is no general way to get an `a` out of `f a` >>>>>>> which cannot be seen by the `Foldable` instance". The use of >>>>>>> `GenericSet` is to handle the case of GADTs, since even parametric >>>>>>> polymorphic functions on them may at given _already known_ types have >>>>>>> specific behaviors. >>>>>>> >>>>>>> This law also works over infinite structures. >>>>>>> >>>>>>> It rules out "obviously wrong" instances and accepts all the >>>>>>> instances >>>>>>> we want to that I am aware of. >>>>>>> >>>>>>> My specific motivation for raising this again is that I am rather >>>>>>> tired of people saying "well, Foldable has no laws, and it is in >>>>>>> base, >>>>>>> so things without laws are just fine." Foldable does a have a law we >>>>>>> all know to obey. It just has been rather tricky to state. The above >>>>>>> provides a decent way to state it. So we should state it. >>>>>>> >>>>>>> Cheers, >>>>>>> Gershom >>>>>>> _______________________________________________ >>>>>>> Libraries mailing list >>>>>>> Libraries at haskell.org >>>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>> >>>>>>> >>>>>>> >>>>>>> _______________________________________________ >>>>>>> Libraries mailing list >>>>>>> Libraries at haskell.org >>>>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>>>> >>>>>>> >>>>>> _______________________________________________ >>>>> Libraries mailing list >>>>> Libraries at haskell.org >>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>>>> >>>>> >>> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Tue May 8 03:19:12 2018 From: david.feuer at gmail.com (David Feuer) Date: Tue, 08 May 2018 03:19:12 +0000 Subject: Proposal: add Bounded instances for Maybe and Either Message-ID: We can write instance Bounded a => Bounded (Maybe a) where minBound = Nothing maxBound = Just maxBound instance (Bounded a, Bounded b) => Bounded (Either a b) where minBound = Left minBound maxBound = Right maxBound While Bounded intentionally does not have an Ord superclass, I think it's worth mentioning that these are the instances that arise naturally from the Ord instances for the types in question. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Tue May 8 03:41:45 2018 From: ekmett at gmail.com (Edward Kmett) Date: Mon, 7 May 2018 23:41:45 -0400 Subject: Proposal: add Bounded instances for Maybe and Either In-Reply-To: References: Message-ID: Clever. I'm surprised those instances weren't already there. On Mon, May 7, 2018 at 11:19 PM, David Feuer wrote: > We can write > > instance Bounded a => Bounded (Maybe a) where > minBound = Nothing > maxBound = Just maxBound > > instance (Bounded a, Bounded b) => Bounded (Either a b) where > minBound = Left minBound > maxBound = Right maxBound > > While Bounded intentionally does not have an Ord superclass, I think it's > worth mentioning that these are the instances that arise naturally from the > Ord instances for the types in question. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ivan.miljenovic at gmail.com Tue May 8 05:06:05 2018 From: ivan.miljenovic at gmail.com (Ivan Lazar Miljenovic) Date: Tue, 8 May 2018 15:06:05 +1000 Subject: Proposal: add Bounded instances for Maybe and Either In-Reply-To: References: Message-ID: On 8 May 2018 at 13:19, David Feuer wrote: > We can write > > instance Bounded a => Bounded (Maybe a) where > minBound = Nothing > maxBound = Just maxBound > > instance (Bounded a, Bounded b) => Bounded (Either a b) where > minBound = Left minBound > maxBound = Right maxBound > > While Bounded intentionally does not have an Ord superclass, I think it's > worth mentioning that these are the instances that arise naturally from the > Ord instances for the types in question. Except these may be surprising to people; e.g. someone may expect that `minBound = Right minBound` as well. Though as Maybe and Either don't have Enum instances this may be less of an issue. -- Ivan Lazar Miljenovic Ivan.Miljenovic at gmail.com http://IvanMiljenovic.wordpress.com From gershomb at gmail.com Tue May 8 05:26:18 2018 From: gershomb at gmail.com (Gershom B) Date: Tue, 8 May 2018 01:26:18 -0400 Subject: Proposal: add Bounded instances for Maybe and Either In-Reply-To: References: Message-ID: On May 8, 2018 at 1:06:24 AM, Ivan Lazar Miljenovic (ivan.miljenovic at gmail.com) wrote: Except these may be surprising to people; e.g. someone may expect that `minBound = Right minBound` as well. Though as Maybe and Either don't have Enum instances this may be less of an issue. Good point — while we’re at it, we should add the Enum instances as well :-) Cheers, Gershom -------------- next part -------------- An HTML attachment was scrubbed... URL: From ivan.miljenovic at gmail.com Tue May 8 06:31:06 2018 From: ivan.miljenovic at gmail.com (Ivan Lazar Miljenovic) Date: Tue, 8 May 2018 16:31:06 +1000 Subject: Proposal: add Bounded instances for Maybe and Either In-Reply-To: References: Message-ID: On 8 May 2018 at 15:26, Gershom B wrote: > On May 8, 2018 at 1:06:24 AM, Ivan Lazar Miljenovic > (ivan.miljenovic at gmail.com) wrote: > > > Except these may be surprising to people; e.g. someone may expect that > `minBound = Right minBound` as well. Though as Maybe and Either don't > have Enum instances this may be less of an issue. > > > Good point — while we’re at it, we should add the Enum instances as well :-) In that case... when do you switch over from Left to Right? -- Ivan Lazar Miljenovic Ivan.Miljenovic at gmail.com http://IvanMiljenovic.wordpress.com From lemming at henning-thielemann.de Tue May 8 06:35:19 2018 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Tue, 8 May 2018 08:35:19 +0200 (CEST) Subject: Proposal: add Bounded instances for Maybe and Either In-Reply-To: References: Message-ID: On Tue, 8 May 2018, Ivan Lazar Miljenovic wrote: > On 8 May 2018 at 15:26, Gershom B wrote: > >> Good point — while we’re at it, we should add the Enum instances as well :-) > > In that case... when do you switch over from Left to Right? I guess when Left maxBound is reached. :-) From zocca.marco at gmail.com Tue May 8 08:58:52 2018 From: zocca.marco at gmail.com (Marco Zocca) Date: Tue, 8 May 2018 10:58:52 +0200 Subject: Taking over `data-default-*` Message-ID: Dear all, I've been increasingly relying on data-default-class, but sadly it doesn't look like it's currently maintained; there are some tickets on the github issue tracker that would need some attention. I have tried contacting the authro/current maintainer Lukas Mai (CC'd) by email but have not received an answer so far (I hope he's doing well, btw). This is my first public request for taking over the `data-default` family of packages: data-default-class data-default-instances-base data-default-instances-containers data-default-instances-dlist data-default-instances-old-locale data-default Kind regards, Marco Zocca (http://hackage.haskell.org/user/ocramz) From ndospark320 at naver.com Tue May 8 14:35:22 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Tue, 08 May 2018 23:35:22 +0900 Subject: =?utf-8?B?UmVzb2x2ZSBuYW1lIGNvbGxzaW9uIG9mIGBmaXJzdGAgYW5kIGBzZWNvbmRgIGJ5IENvbg==?= =?utf-8?B?dHJvbC5BcnJvdyBhbmQgRGF0YS5CaWZ1bmN0b3I=?= References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> Message-ID: I had to import both Control.Arrow and Data.Bifunctor, and the name collision is annoying. `first` and `second` from Data.Bifunctor should be given other names. I suggest (<$<) and (>$>), respectively. -------------- next part -------------- An HTML attachment was scrubbed... URL: From alexandrer_b at outlook.com Tue May 8 14:57:40 2018 From: alexandrer_b at outlook.com (Alexandre Rodrigues) Date: Tue, 8 May 2018 14:57:40 +0000 Subject: Resolve name collsion of `first` and `second` by Control.Arrow and Data.Bifunctor In-Reply-To: References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> Message-ID: Name collisions are always an issue, and I think you raise a valid point. However, in this case, does Haskell not already offer a solution? Qualified imports do add some overhead, but doing ``` import qualified Control.Arrow as A import qualified Data.Bifunctor as B foo :: Foo foo = f . A.first . g baz :: Baz baz = h . B.first . i ``` does not seem too difficult. On 08-05-2018 15:35, 박신환 wrote: I had to import both Control.Arrow and Data.Bifunctor, and the name collision is annoying. `first` and `second` from Data.Bifunctor should be given other names. I suggest (<$<) and (>$>), respectively. [https://mail.naver.com/readReceipt/notify/?img=JeRCbHFTpz%2FYaqgZKrRZpzK%2FMoE%2FKoFvF4Mqp6JopACSMovdpxkvFx%2B0M6t9tzFXp6UwaLl5WLl51zlqDBFdp6d5MreRhoRn16iZMBiGpBFg1zJq1rknWVlTb4b%3D.gif] _______________________________________________ Libraries mailing list Libraries at haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From emertens at gmail.com Tue May 8 16:04:12 2018 From: emertens at gmail.com (Eric Mertens) Date: Tue, 08 May 2018 16:04:12 +0000 Subject: Resolve name collsion of `first` and `second` by Control.Arrow and Data.Bifunctor In-Reply-To: References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> Message-ID: I'm opposed to changing the names in either module. In modern code it should be fairly rare to import Control.Arrow. In the cases that both are needed qualified imports are available, and it wouldn't be worth breaking existing code by renaming the class methods of Bifunctor. On Tue, May 8, 2018 at 7:58 AM Alexandre Rodrigues wrote: > Name collisions are always an issue, and I think you raise a valid point. > However, in this case, does Haskell not already offer a solution? Qualified > imports do add some overhead, but doing > > ``` > > import qualified Control.Arrow as A > > import qualified Data.Bifunctor as B > > > foo :: Foo > > foo = f . A.first . g > > > baz :: Baz > > baz = h . B.first . i > > ``` > > does not seem too difficult. > > On 08-05-2018 15:35, 박신환 wrote: > > I had to import both Control.Arrow and Data.Bifunctor, and the name > collision is annoying. > > > > `first` and `second` from Data.Bifunctor should be given other names. I > suggest (<$<) and (>$>), respectively. > > > _______________________________________________ > Libraries mailing listLibraries at haskell.orghttp://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Wed May 9 02:15:40 2018 From: ekmett at gmail.com (Edward Kmett) Date: Tue, 8 May 2018 22:15:40 -0400 Subject: Proposal: add Bounded instances for Maybe and Either In-Reply-To: References: Message-ID: minBound = Left minBound <= Left a < Right b <= Right maxBound = maxBound fits with the behavior of the existing Ord instance. On the other hand, Left (), being strictly less than minBound would rather drastically undermine the expected interaction of Ord and Bounded. -Edward On Tue, May 8, 2018 at 1:06 AM, Ivan Lazar Miljenovic < ivan.miljenovic at gmail.com> wrote: > On 8 May 2018 at 13:19, David Feuer wrote: > > We can write > > > > instance Bounded a => Bounded (Maybe a) where > > minBound = Nothing > > maxBound = Just maxBound > > > > instance (Bounded a, Bounded b) => Bounded (Either a b) where > > minBound = Left minBound > > maxBound = Right maxBound > > > > While Bounded intentionally does not have an Ord superclass, I think it's > > worth mentioning that these are the instances that arise naturally from > the > > Ord instances for the types in question. > > Except these may be surprising to people; e.g. someone may expect that > `minBound = Right minBound` as well. Though as Maybe and Either don't > have Enum instances this may be less of an issue. > > -- > Ivan Lazar Miljenovic > Ivan.Miljenovic at gmail.com > http://IvanMiljenovic.wordpress.com > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ivan.miljenovic at gmail.com Wed May 9 04:30:02 2018 From: ivan.miljenovic at gmail.com (Ivan Lazar Miljenovic) Date: Wed, 9 May 2018 14:30:02 +1000 Subject: Proposal: add Bounded instances for Maybe and Either In-Reply-To: References: Message-ID: On 9 May 2018 at 12:15, Edward Kmett wrote: > minBound = Left minBound <= Left a < Right b <= Right maxBound = maxBound > > fits with the behavior of the existing Ord instance. > > On the other hand, Left (), being strictly less than minBound would rather > drastically undermine the expected interaction of Ord and Bounded. Fair enough. I had also missed in David's initial proposal that we had Bounded on both a and b in (Either a b). I'm +1 on these instances (more from a "they're the logical instances" PoV than "this will be useful"). -- Ivan Lazar Miljenovic Ivan.Miljenovic at gmail.com http://IvanMiljenovic.wordpress.com From ndospark320 at naver.com Wed May 9 06:34:11 2018 From: ndospark320 at naver.com (=?utf-8?B?67CV7Iug7ZmY?=) Date: Wed, 09 May 2018 15:34:11 +0900 Subject: =?utf-8?B?UmU6IFJlc29sdmUgbmFtZSBjb2xsc2lvbiBvZiBgZmlyc3RgIGFuZCBgc2Vjb25kYCBieQ==?= =?utf-8?B?IENvbnRyb2wuQXJyb3cgYW5kIERhdGEuQmlmdW5jdG9y?= In-Reply-To: References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> Message-ID: It still seems worthy to add the aliases for Data.Bifunctor.first and Data.Bifunctor.second. Hence: import Control.Arrow import Data.Bifunctor hiding (first, second) and we don't need to have the methods qualified. -----Original Message----- From: "Eric Mertens" To: "Alexandre Rodrigues"; Cc: "박신환"; "Haskell Libraries"; Sent: 2018-05-09 (수) 01:04:12 Subject: Re: Resolve name collsion of `first` and `second` by Control.Arrow and Data.Bifunctor I'm opposed to changing the names in either module. In modern code it should be fairly rare to import Control.Arrow. In the cases that both are needed qualified imports are available, and it wouldn't be worth breaking existing code by renaming the class methods of Bifunctor. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ekmett at gmail.com Wed May 9 06:57:43 2018 From: ekmett at gmail.com (Edward Kmett) Date: Wed, 9 May 2018 02:57:43 -0400 Subject: Resolve name collsion of `first` and `second` by Control.Arrow and Data.Bifunctor In-Reply-To: References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> Message-ID: It is worth noting that first and second from Data.Bifunctor were named to serve as an argument that in general it is seems useful to abstract over the bifunctor than the arrow type, in an attempt to help lead people away from Control.Arrow. My experience and the data I had at the time based on data mining hackage was that most of the code that was importing Control.Arrow, was importing it to work with just the (->) instane, and to get a couple of combinators like first and second. The clash was a rather deliberate choice. Data.Profunctor, which offered yet a third color for the bikeshed actually deliberately moving "out of the way" of the names taken by Data.Bifunctor and Control.Arrow and I've pretty much regretted the ' s in the names ever since. So I'm not terribly inclined to rename the combinators that live in each one of the classes. On the other hand, exporting redundant alternatively named aliases from the module would then introduce yet another name for people to get hung up on, and if it has exactly the same type signature they'd have to then know which one was in the class and which one is not. This is rather annoying and hard to keep track of information. But it is worth noting that 'import ... as ...' doesnt required the use of qualified, so with import Control.Arrow as A import Data.Bifunctor as B now you can use almost all the combinators and operators from Control.Arrow except first and second unqualified _and_ almost all the combinators from Data.Bifunctor unqualified, but need to refer to A.first or B.first and A.second or B.second due to the clash. This can be locally disambiguated by users with no additional information about what has been added in some bleeding edge version of Data.Bifunctor. We have qualified imports for covering this scenario. Globally unique names are generally going to be impossible to maintain, and additional redundant aliases come with additional cognitive overhead to remember that they exist, and which one is the redefinable one that lives in the class, so this request doesn't come 'for free'. -Edward On Wed, May 9, 2018 at 2:34 AM, 박신환 wrote: > It still seems worthy to add the aliases for Data.Bifunctor.first and > Data.Bifunctor.second. Hence: > > > > import Control.Arrow > > import Data.Bifunctor hiding (first, second) > > > > and we don't need to have the methods qualified. > > > > -----Original Message----- > *From:* "Eric Mertens" > *To:* "Alexandre Rodrigues"; > *Cc:* "박신환"; "Haskell Libraries" org>; > *Sent:* 2018-05-09 (수) 01:04:12 > *Subject:* Re: Resolve name collsion of `first` and `second` by > Control.Arrow and Data.Bifunctor > > I'm opposed to changing the names in either module. In modern code it > should be fairly rare to import Control.Arrow. In the cases that both are > needed qualified imports are available, and it wouldn't be worth breaking > existing code by renaming the class methods of Bifunctor. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From wolfgang-it at jeltsch.info Wed May 9 10:57:02 2018 From: wolfgang-it at jeltsch.info (Wolfgang Jeltsch) Date: Wed, 09 May 2018 13:57:02 +0300 Subject: Resolve name collsion of `first` and `second` by Control.Arrow and Data.Bifunctor In-Reply-To: References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> Message-ID: <1525863422.3990.75.camel@jeltsch.info> Eric Mertens wrote: > In modern code it should be fairly rare to import Control.Arrow.  Edward Kmett wrote: > […] in an attempt to help lead people away from > Control.Arrow> . I’m irritated. Can someone explain what is wrong about Control.Arrow? All the best, Wolfgang -------------- next part -------------- An HTML attachment was scrubbed... URL: From lemming at henning-thielemann.de Wed May 9 11:49:56 2018 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Wed, 9 May 2018 13:49:56 +0200 (CEST) Subject: Resolve name collsion of `first` and `second` by Control.Arrow and Data.Bifunctor In-Reply-To: <1525863422.3990.75.camel@jeltsch.info> References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> <1525863422.3990.75.camel@jeltsch.info> Message-ID: On Wed, 9 May 2018, Wolfgang Jeltsch wrote: > Eric Mertens wrote: > > In modern code it should be fairly rare to import Control.Arrow.  > > > Edward Kmett wrote: > > […] in an attempt to help lead people away from Control.Arrow. > > > I’m irritated. Can someone explain what is wrong about Control.Arrow? I think there is nothing wrong about Arrow, but people abused Arrow.first and Arrow.second for plain function arrow and now we have Bifunctor which is the more appropriate abstraction for most uses of 'first' and 'second'. (Though I guess that most uses need no abstraction at all.) From wolfgang-it at jeltsch.info Wed May 9 12:59:46 2018 From: wolfgang-it at jeltsch.info (Wolfgang Jeltsch) Date: Wed, 09 May 2018 15:59:46 +0300 Subject: Resolve name collsion of `first` and `second` by Control.Arrow and Data.Bifunctor In-Reply-To: References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> <1525863422.3990.75.camel@jeltsch.info> Message-ID: <1525870786.3990.91.camel@jeltsch.info> Am Mittwoch, den 09.05.2018, 13:49 +0200 schrieb Henning Thielemann: > On Wed, 9 May 2018, Wolfgang Jeltsch wrote: > > > > > Eric Mertens wrote: > > > >       In modern code it should be fairly rare to import > >       Control.Arrow.  > > > > > > Edward Kmett wrote: > > > >       […] in an attempt to help lead people away from Control.Arrow. > > > > > > I’m irritated. Can someone explain what is wrong about > > Control.Arrow? > > I think there is nothing wrong about Arrow, but people abused > Arrow.first and Arrow.second for plain function arrow and now we have > Bifunctor which is the more appropriate abstraction for most uses of > 'first' and 'second'. (Though I guess that most uses need no > abstraction at all.) I think using Bifunctor.first and Bifunctor.second is as much an abuse as using Arrow.first and Arrow.second. When using Arrow you specialize the arrow type to (->), but when using Bifunctor you specialize the bifunctor type to (,). All the best, Wolfgang From david.feuer at gmail.com Thu May 10 01:11:48 2018 From: david.feuer at gmail.com (David Feuer) Date: Thu, 10 May 2018 01:11:48 +0000 Subject: Proposal: Continue the displayException program Message-ID: Several years ago, Michael Snoyman proposed [*] that we add a displayException method to the Exception class, and that we make GHC use it in the default handler. The first part of that proposal was accepted and implemented, but the second part was not, for reasons that are not very clear to me. I would like to re-propose that we change the default exception handler to use displayException instead of Show. This seems like a much better default, and anyone who wants to do it the old way can still change the top-level handler. [*] https://mail.haskell.org/pipermail/libraries/2014-November/024176.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From emertens at gmail.com Thu May 10 01:35:30 2018 From: emertens at gmail.com (Eric Mertens) Date: Wed, 9 May 2018 18:35:30 -0700 Subject: Proposal: Continue the displayException program In-Reply-To: References: Message-ID: It looks like the original objection is that using displayException makes it harder for the programmer to determine how to handle the exception and that uncaught exceptions were expected to be mostly seen by the developer. This kind of problem certainly comes up when we have to consult the GHC sources to map IOError error message text back to the correct predicate function to use to test for an exception. Part of the original discussion on this topic included some ideas for ways to make it easier to install an uncaught exception handler that would use displayException instead of the default show. Maybe it would be a good time to entertain some progress on those? > On May 9, 2018, at 6:11 PM, David Feuer wrote: > > Several years ago, Michael Snoyman proposed [*] that we add a displayException method to the Exception class, and that we make GHC use it in the default handler. The first part of that proposal was accepted and implemented, but the second part was not, for reasons that are not very clear to me. I would like to re-propose that we change the default exception handler to use displayException instead of Show. This seems like a much better default, and anyone who wants to do it the old way can still change the top-level handler. > > [*] https://mail.haskell.org/pipermail/libraries/2014-November/024176.html _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From michael at snoyman.com Thu May 10 03:44:55 2018 From: michael at snoyman.com (Michael Snoyman) Date: Thu, 10 May 2018 03:44:55 +0000 Subject: Proposal: Continue the displayException program In-Reply-To: References: Message-ID: As I'm guessing you'd expect, I'm +1 on this. On Thu, May 10, 2018, 4:12 AM David Feuer wrote: > Several years ago, Michael Snoyman proposed [*] that we add a > displayException method to the Exception class, and that we make GHC use it > in the default handler. The first part of that proposal was accepted and > implemented, but the second part was not, for reasons that are not very > clear to me. I would like to re-propose that we change the default > exception handler to use displayException instead of Show. This seems like > a much better default, and anyone who wants to do it the old way can still > change the top-level handler. > > [*] https://mail.haskell.org/pipermail/libraries/2014-November/024176.html > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From oleg.grenrus at iki.fi Sat May 12 22:22:41 2018 From: oleg.grenrus at iki.fi (Oleg Grenrus) Date: Sun, 13 May 2018 01:22:41 +0300 Subject: Package take over: OneTuple In-Reply-To: References: Message-ID: <484b99c1-c9b5-6296-3f12-aff05864a7cf@iki.fi> I were granted maintainer bits on OneTuple, I now upload https://hackage.haskell.org/package/OneTuple-0.2.2 which is compatible with GHC-8.4 Cheers, Oleg On 13.04.2018 15:28, Oleg Grenrus wrote: > Hi all, > > I tried to contact John Dorsey who is the sole maintainer of OneTuple > [1], but the stated email address (haskell at colquitt.org) bounces back. > > The last version of  OneTuple was uploaded "by JohnDorsey at Tue Mar 24 > 17:35:51 UTC 2009" - 9 years ago. OneTuple was working great so far, but > GHC-8.4.1 / base-4.11 introduced breaking change, which affects  > OneTuple too: Semigroup is now a superclass of Monoid. Therefore none of > OneTuple versions is GHC-8.4.1/base-4.11 compatible. > > I'm a Hackage Trustee [1] and also a user of OneTuple package (though > not direct - it's in the transitive closure of Chart + diagrams), so I'd > like to see GHC-8.4 compatible OneTuple version soon. > > The required changes are very small, see  > https://github.com/phadej/OneTuple/pull/1 or more precisely this exact > commit: > https://github.com/phadej/OneTuple/pull/1/commits/1dbc4d3186f707034953e131995c590eb50cd9af > > I'd like to become (co-)maintainer of OneTuple. I have no other plans > than to keep it compiling with recent versions of GHC. Maybe I'll add > NFData (from `deepseq`) instance though. > > Best Regards, Oleg Grenrus > > > [1]:  https://hackage.haskell.org/package/OneTuple > > > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: OpenPGP digital signature URL: From lemming at henning-thielemann.de Fri May 18 07:13:23 2018 From: lemming at henning-thielemann.de (Henning Thielemann) Date: Fri, 18 May 2018 09:13:23 +0200 (CEST) Subject: Resolve name collsion of `first` and `second` by Control.Arrow and Data.Bifunctor In-Reply-To: <1525870786.3990.91.camel@jeltsch.info> References: <9b94025f8172fa7348587c707ee742@cweb17.nm.nhnsystem.com> <1525863422.3990.75.camel@jeltsch.info> <1525870786.3990.91.camel@jeltsch.info> Message-ID: On Wed, 9 May 2018, Wolfgang Jeltsch wrote: > I think using Bifunctor.first and Bifunctor.second is as much an abuse > as using Arrow.first and Arrow.second. When using Arrow you specialize > the arrow type to (->), but when using Bifunctor you specialize the > bifunctor type to (,). I actually use my own specialised mapFst and mapSnd functions from utility-ht. I also found that I sometimes need strict versions of these functions in order to prevent space leaks. From mail at doisinkidney.com Tue May 22 21:57:29 2018 From: mail at doisinkidney.com (=?utf-8?Q?Donnacha_Ois=C3=ADn_Kidney?=) Date: Tue, 22 May 2018 17:57:29 -0400 Subject: Strictness of Semigroup instance for Maybe Message-ID: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> The current semigroup instance for Maybe looks like this: instance Semigroup a => Semigroup (Maybe a) where Nothing <> b = b a <> Nothing = a Just a <> Just b = Just (a <> b) However, it could be lazier: instance Semigroup a => Semigroup (Maybe a) where Nothing <> b = b Just a <> b = Just (maybe a (a<>) b) This causes different behaviour for Data.Semigroup.First and Data.Monoid.First : >>> Data.Monoid.getFirst . foldMap pure $ [1..] Just 1 >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . foldMap (pure.pure) $ [1..] _|_ A different definition for `Option` gets back the old behaviour: newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } instance Semigroup a => Semigroup (LeftOption a) where LeftOption Nothing <> ys = ys LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x (x<>) ys)) instance Semigroup a => Monoid (LeftOption a) where mempty = LeftOption Nothing mappend = (<>) >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap (LeftOption . Just . Data.Semigroup.First) $ [1..] Just 1 Is there any benefit to the extra strictness? Should this be changed? Another consideration is that the definition could equivalently be right-strict, to get the desired behaviour for Last, but I think the left-strict definition probably follows the conventions more. I originally posted this to reddit (https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_maybe_too_strict/ ) and was encouraged to post it here. -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Tue May 22 23:37:42 2018 From: david.feuer at gmail.com (David Feuer) Date: Tue, 22 May 2018 19:37:42 -0400 Subject: Strictness of Semigroup instance for Maybe In-Reply-To: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> References: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> Message-ID: I think extra laziness here would be a bit surprising. On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney wrote: > The current semigroup instance for Maybe looks like this: > > instance Semigroup a => Semigroup (Maybe a) where > Nothing <> b = b > a <> Nothing = a > Just a <> Just b = Just (a <> b) > > However, it could be lazier: > > instance Semigroup a => Semigroup (Maybe a) where > Nothing <> b = b > Just a <> b = Just (maybe a (a<>) b) > > This causes different behaviour for Data.Semigroup.First and > Data.Monoid.First: > > >>> Data.Monoid.getFirst . foldMap pure $ [1..] > Just 1 > >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . foldMap > (pure.pure) $ [1..] > _|_ > > A different definition for `Option` gets back the old behaviour: > > newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } > > instance Semigroup a => Semigroup (LeftOption a) where > LeftOption Nothing <> ys = ys > LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x (x<>) > ys)) > > instance Semigroup a => Monoid (LeftOption a) where > mempty = LeftOption Nothing > mappend = (<>) > > >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap (LeftOption . > Just . Data.Semigroup.First) $ [1..] > Just 1 > > Is there any benefit to the extra strictness? Should this be changed? > > Another consideration is that the definition could equivalently be > right-strict, to get the desired behaviour for Last, but I think the > left-strict definition probably follows the conventions more. > > I originally posted this to reddit > (https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_maybe_too_strict/) > and was encouraged to post it here. > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > From tikhon at jelv.is Tue May 22 23:57:32 2018 From: tikhon at jelv.is (Tikhon Jelvis) Date: Tue, 22 May 2018 16:57:32 -0700 Subject: Strictness of Semigroup instance for Maybe In-Reply-To: References: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> Message-ID: I think the extra laziness makes sense here—it matches the behavior of common functions like &&. My general expectation is that functions are as lazy as they can be and, in the case of operators with two arguments, that evaluation goes left-to-right. (Again like &&.) On Tue, May 22, 2018 at 4:37 PM, David Feuer wrote: > I think extra laziness here would be a bit surprising. > > On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney > wrote: > > The current semigroup instance for Maybe looks like this: > > > > instance Semigroup a => Semigroup (Maybe a) where > > Nothing <> b = b > > a <> Nothing = a > > Just a <> Just b = Just (a <> b) > > > > However, it could be lazier: > > > > instance Semigroup a => Semigroup (Maybe a) where > > Nothing <> b = b > > Just a <> b = Just (maybe a (a<>) b) > > > > This causes different behaviour for Data.Semigroup.First and > > Data.Monoid.First: > > > > >>> Data.Monoid.getFirst . foldMap pure $ [1..] > > Just 1 > > >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . > foldMap > > (pure.pure) $ [1..] > > _|_ > > > > A different definition for `Option` gets back the old behaviour: > > > > newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } > > > > instance Semigroup a => Semigroup (LeftOption a) where > > LeftOption Nothing <> ys = ys > > LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x > (x<>) > > ys)) > > > > instance Semigroup a => Monoid (LeftOption a) where > > mempty = LeftOption Nothing > > mappend = (<>) > > > > >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap > (LeftOption . > > Just . Data.Semigroup.First) $ [1..] > > Just 1 > > > > Is there any benefit to the extra strictness? Should this be changed? > > > > Another consideration is that the definition could equivalently be > > right-strict, to get the desired behaviour for Last, but I think the > > left-strict definition probably follows the conventions more. > > > > I originally posted this to reddit > > (https://www.reddit.com/r/haskell/comments/8lbzan/ > semigroup_maybe_too_strict/) > > and was encouraged to post it here. > > > > _______________________________________________ > > Libraries mailing list > > Libraries at haskell.org > > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ryan.reich at gmail.com Wed May 23 01:19:19 2018 From: ryan.reich at gmail.com (Ryan Reich) Date: Tue, 22 May 2018 18:19:19 -0700 Subject: Strictness of Semigroup instance for Maybe In-Reply-To: References: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> Message-ID: I second this expectation. I've recently had a hard time ensuring laziness in my work and it's been comforting in rooting out failures to know that the standard libraries, at least, are concerned about it. On Tue, May 22, 2018, 16:57 Tikhon Jelvis wrote: > I think the extra laziness makes sense here—it matches the behavior of > common functions like &&. My general expectation is that functions are as > lazy as they can be and, in the case of operators with two arguments, that > evaluation goes left-to-right. (Again like &&.) > > On Tue, May 22, 2018 at 4:37 PM, David Feuer > wrote: > >> I think extra laziness here would be a bit surprising. >> >> On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney >> wrote: >> > The current semigroup instance for Maybe looks like this: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > a <> Nothing = a >> > Just a <> Just b = Just (a <> b) >> > >> > However, it could be lazier: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > Just a <> b = Just (maybe a (a<>) b) >> > >> > This causes different behaviour for Data.Semigroup.First and >> > Data.Monoid.First: >> > >> > >>> Data.Monoid.getFirst . foldMap pure $ [1..] >> > Just 1 >> > >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . >> foldMap >> > (pure.pure) $ [1..] >> > _|_ >> > >> > A different definition for `Option` gets back the old behaviour: >> > >> > newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } >> > >> > instance Semigroup a => Semigroup (LeftOption a) where >> > LeftOption Nothing <> ys = ys >> > LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x >> (x<>) >> > ys)) >> > >> > instance Semigroup a => Monoid (LeftOption a) where >> > mempty = LeftOption Nothing >> > mappend = (<>) >> > >> > >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap >> (LeftOption . >> > Just . Data.Semigroup.First) $ [1..] >> > Just 1 >> > >> > Is there any benefit to the extra strictness? Should this be changed? >> > >> > Another consideration is that the definition could equivalently be >> > right-strict, to get the desired behaviour for Last, but I think the >> > left-strict definition probably follows the conventions more. >> > >> > I originally posted this to reddit >> > ( >> https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_maybe_too_strict/ >> ) >> > and was encouraged to post it here. >> > >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrew.thaddeus at gmail.com Wed May 23 11:21:04 2018 From: andrew.thaddeus at gmail.com (Andrew Martin) Date: Wed, 23 May 2018 07:21:04 -0400 Subject: Strictness of Semigroup instance for Maybe In-Reply-To: References: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> Message-ID: I feel the the way concerning being lazy as possible and being left-strict where there is a symmetric choice to be made. This seems to be a common theme is base, although I’ve never seen it officially endorsed. I have seen Edward Kmett talk about this on reddit (contrasting it with the Monoid classes in strict-by-default languages), but I cannot find the thread. Sent from my iPhone > On May 22, 2018, at 7:57 PM, Tikhon Jelvis wrote: > > I think the extra laziness makes sense here—it matches the behavior of common functions like &&. My general expectation is that functions are as lazy as they can be and, in the case of operators with two arguments, that evaluation goes left-to-right. (Again like &&.) > >> On Tue, May 22, 2018 at 4:37 PM, David Feuer wrote: >> I think extra laziness here would be a bit surprising. >> >> On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney >> wrote: >> > The current semigroup instance for Maybe looks like this: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > a <> Nothing = a >> > Just a <> Just b = Just (a <> b) >> > >> > However, it could be lazier: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > Just a <> b = Just (maybe a (a<>) b) >> > >> > This causes different behaviour for Data.Semigroup.First and >> > Data.Monoid.First: >> > >> > >>> Data.Monoid.getFirst . foldMap pure $ [1..] >> > Just 1 >> > >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . foldMap >> > (pure.pure) $ [1..] >> > _|_ >> > >> > A different definition for `Option` gets back the old behaviour: >> > >> > newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } >> > >> > instance Semigroup a => Semigroup (LeftOption a) where >> > LeftOption Nothing <> ys = ys >> > LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x (x<>) >> > ys)) >> > >> > instance Semigroup a => Monoid (LeftOption a) where >> > mempty = LeftOption Nothing >> > mappend = (<>) >> > >> > >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap (LeftOption . >> > Just . Data.Semigroup.First) $ [1..] >> > Just 1 >> > >> > Is there any benefit to the extra strictness? Should this be changed? >> > >> > Another consideration is that the definition could equivalently be >> > right-strict, to get the desired behaviour for Last, but I think the >> > left-strict definition probably follows the conventions more. >> > >> > I originally posted this to reddit >> > (https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_maybe_too_strict/) >> > and was encouraged to post it here. >> > >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From emertens at gmail.com Wed May 23 15:14:33 2018 From: emertens at gmail.com (Eric Mertens) Date: Wed, 23 May 2018 08:14:33 -0700 Subject: Strictness of Semigroup instance for Maybe In-Reply-To: References: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> Message-ID: Hello, I think changing the strictness of this function could have potentially dramatic performance effects on a wide range of existing code. Exploring existing code to understand the exact impacts would be a huge challenge, and this is a change that would be hard to phase in. The arbitrariness of decisions like this is part of what makes the Monoid class a mess in the first place. Attaching instances like this to otherwise generic types forces us to make arbitrary choices, which are often not documented on the instances themselves. While the left-bias behavior might make sense in the case of an instance like we have for First, I don't see why it would be considered more correct in this case. I'm -1 on this proposal. Best regards, Eric Mertens On Wed, May 23, 2018 at 4:21 AM Andrew Martin wrote: > I feel the the way concerning being lazy as possible and being left-strict > where there is a symmetric choice to be made. This seems to be a common > theme is base, although I’ve never seen it officially endorsed. I have seen > Edward Kmett talk about this on reddit (contrasting it with the Monoid > classes in strict-by-default languages), but I cannot find the thread. > > Sent from my iPhone > > On May 22, 2018, at 7:57 PM, Tikhon Jelvis wrote: > > I think the extra laziness makes sense here—it matches the behavior of > common functions like &&. My general expectation is that functions are as > lazy as they can be and, in the case of operators with two arguments, that > evaluation goes left-to-right. (Again like &&.) > > On Tue, May 22, 2018 at 4:37 PM, David Feuer > wrote: > >> I think extra laziness here would be a bit surprising. >> >> On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney >> wrote: >> > The current semigroup instance for Maybe looks like this: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > a <> Nothing = a >> > Just a <> Just b = Just (a <> b) >> > >> > However, it could be lazier: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > Just a <> b = Just (maybe a (a<>) b) >> > >> > This causes different behaviour for Data.Semigroup.First and >> > Data.Monoid.First: >> > >> > >>> Data.Monoid.getFirst . foldMap pure $ [1..] >> > Just 1 >> > >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . >> foldMap >> > (pure.pure) $ [1..] >> > _|_ >> > >> > A different definition for `Option` gets back the old behaviour: >> > >> > newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } >> > >> > instance Semigroup a => Semigroup (LeftOption a) where >> > LeftOption Nothing <> ys = ys >> > LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x >> (x<>) >> > ys)) >> > >> > instance Semigroup a => Monoid (LeftOption a) where >> > mempty = LeftOption Nothing >> > mappend = (<>) >> > >> > >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap >> (LeftOption . >> > Just . Data.Semigroup.First) $ [1..] >> > Just 1 >> > >> > Is there any benefit to the extra strictness? Should this be changed? >> > >> > Another consideration is that the definition could equivalently be >> > right-strict, to get the desired behaviour for Last, but I think the >> > left-strict definition probably follows the conventions more. >> > >> > I originally posted this to reddit >> > ( >> https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_maybe_too_strict/ >> ) >> > and was encouraged to post it here. >> > >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed May 23 18:54:48 2018 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Wed, 23 May 2018 14:54:48 -0400 Subject: Strictness of Semigroup instance for Maybe In-Reply-To: References: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> Message-ID: yeah ... i agreed with Eric, we almost need Lazy and Strict versions of monoid and each blows up in different ways. I definitely had epic space leaks from the lazy Maybe Monoid -1 :) On Wed, May 23, 2018 at 11:14 AM, Eric Mertens wrote: > Hello, > > I think changing the strictness of this function could have potentially > dramatic performance effects on a wide range of existing code. Exploring > existing code to understand the exact impacts would be a huge challenge, > and this is a change that would be hard to phase in. > > The arbitrariness of decisions like this is part of what makes the Monoid > class a mess in the first place. Attaching instances like this to otherwise > generic types forces us to make arbitrary choices, which are often not > documented on the instances themselves. > > While the left-bias behavior might make sense in the case of an instance > like we have for First, I don't see why it would be considered more correct > in this case. > > I'm -1 on this proposal. > > Best regards, > Eric Mertens > > On Wed, May 23, 2018 at 4:21 AM Andrew Martin > wrote: > >> I feel the the way concerning being lazy as possible and being >> left-strict where there is a symmetric choice to be made. This seems to be >> a common theme is base, although I’ve never seen it officially endorsed. I >> have seen Edward Kmett talk about this on reddit (contrasting it with the >> Monoid classes in strict-by-default languages), but I cannot find the >> thread. >> >> Sent from my iPhone >> >> On May 22, 2018, at 7:57 PM, Tikhon Jelvis wrote: >> >> I think the extra laziness makes sense here—it matches the behavior of >> common functions like &&. My general expectation is that functions are as >> lazy as they can be and, in the case of operators with two arguments, that >> evaluation goes left-to-right. (Again like &&.) >> >> On Tue, May 22, 2018 at 4:37 PM, David Feuer >> wrote: >> >>> I think extra laziness here would be a bit surprising. >>> >>> On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney >>> wrote: >>> > The current semigroup instance for Maybe looks like this: >>> > >>> > instance Semigroup a => Semigroup (Maybe a) where >>> > Nothing <> b = b >>> > a <> Nothing = a >>> > Just a <> Just b = Just (a <> b) >>> > >>> > However, it could be lazier: >>> > >>> > instance Semigroup a => Semigroup (Maybe a) where >>> > Nothing <> b = b >>> > Just a <> b = Just (maybe a (a<>) b) >>> > >>> > This causes different behaviour for Data.Semigroup.First and >>> > Data.Monoid.First: >>> > >>> > >>> Data.Monoid.getFirst . foldMap pure $ [1..] >>> > Just 1 >>> > >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . >>> foldMap >>> > (pure.pure) $ [1..] >>> > _|_ >>> > >>> > A different definition for `Option` gets back the old behaviour: >>> > >>> > newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } >>> > >>> > instance Semigroup a => Semigroup (LeftOption a) where >>> > LeftOption Nothing <> ys = ys >>> > LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x >>> (x<>) >>> > ys)) >>> > >>> > instance Semigroup a => Monoid (LeftOption a) where >>> > mempty = LeftOption Nothing >>> > mappend = (<>) >>> > >>> > >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap >>> (LeftOption . >>> > Just . Data.Semigroup.First) $ [1..] >>> > Just 1 >>> > >>> > Is there any benefit to the extra strictness? Should this be changed? >>> > >>> > Another consideration is that the definition could equivalently be >>> > right-strict, to get the desired behaviour for Last, but I think the >>> > left-strict definition probably follows the conventions more. >>> > >>> > I originally posted this to reddit >>> > (https://www.reddit.com/r/haskell/comments/8lbzan/ >>> semigroup_maybe_too_strict/) >>> > and was encouraged to post it here. >>> > >>> > _______________________________________________ >>> > Libraries mailing list >>> > Libraries at haskell.org >>> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> > >>> _______________________________________________ >>> Libraries mailing list >>> Libraries at haskell.org >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >>> >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mail at doisinkidney.com Wed May 23 19:39:17 2018 From: mail at doisinkidney.com (=?utf-8?Q?Donnacha_Ois=C3=ADn_Kidney?=) Date: Wed, 23 May 2018 15:39:17 -0400 Subject: Strictness of Semigroup instance for Maybe In-Reply-To: References: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> Message-ID: <8C414634-29B2-4EDA-AF8B-36984671B487@doisinkidney.com> Not sure if I’m correct on this, but wouldn’t you get space leaks in the right-strict version as well? Because the Just constructor itself isn’t strict, you still build up a long chain of <>. In the right-lazy version, you build up a long chain of maybe a (a<>), which is more expensive, yes, but not asymptotically. In other words, if you’ve got a space leak in the right-lazy version, you’ll also have one in the right-strict version. > On 23 May 2018, at 14:54, Carter Schonwald wrote: > > yeah ... i agreed with Eric, > we almost need Lazy and Strict versions of monoid and each blows up in different ways. I definitely had epic space leaks from the lazy Maybe Monoid > > -1 :) > > On Wed, May 23, 2018 at 11:14 AM, Eric Mertens > wrote: > Hello, > > I think changing the strictness of this function could have potentially dramatic performance effects on a wide range of existing code. Exploring existing code to understand the exact impacts would be a huge challenge, and this is a change that would be hard to phase in. > > The arbitrariness of decisions like this is part of what makes the Monoid class a mess in the first place. Attaching instances like this to otherwise generic types forces us to make arbitrary choices, which are often not documented on the instances themselves. > > While the left-bias behavior might make sense in the case of an instance like we have for First, I don't see why it would be considered more correct in this case. > > I'm -1 on this proposal. > > Best regards, > Eric Mertens > > On Wed, May 23, 2018 at 4:21 AM Andrew Martin > wrote: > I feel the the way concerning being lazy as possible and being left-strict where there is a symmetric choice to be made. This seems to be a common theme is base, although I’ve never seen it officially endorsed. I have seen Edward Kmett talk about this on reddit (contrasting it with the Monoid classes in strict-by-default languages), but I cannot find the thread. > > Sent from my iPhone > > On May 22, 2018, at 7:57 PM, Tikhon Jelvis > wrote: > >> I think the extra laziness makes sense here—it matches the behavior of common functions like &&. My general expectation is that functions are as lazy as they can be and, in the case of operators with two arguments, that evaluation goes left-to-right. (Again like &&.) >> >> On Tue, May 22, 2018 at 4:37 PM, David Feuer > wrote: >> I think extra laziness here would be a bit surprising. >> >> On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney >> > wrote: >> > The current semigroup instance for Maybe looks like this: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > a <> Nothing = a >> > Just a <> Just b = Just (a <> b) >> > >> > However, it could be lazier: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > Just a <> b = Just (maybe a (a<>) b) >> > >> > This causes different behaviour for Data.Semigroup.First and >> > Data.Monoid.First: >> > >> > >>> Data.Monoid.getFirst . foldMap pure $ [1..] >> > Just 1 >> > >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . foldMap >> > (pure.pure) $ [1..] >> > _|_ >> > >> > A different definition for `Option` gets back the old behaviour: >> > >> > newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } >> > >> > instance Semigroup a => Semigroup (LeftOption a) where >> > LeftOption Nothing <> ys = ys >> > LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x (x<>) >> > ys)) >> > >> > instance Semigroup a => Monoid (LeftOption a) where >> > mempty = LeftOption Nothing >> > mappend = (<>) >> > >> > >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap (LeftOption . >> > Just . Data.Semigroup.First) $ [1..] >> > Just 1 >> > >> > Is there any benefit to the extra strictness? Should this be changed? >> > >> > Another consideration is that the definition could equivalently be >> > right-strict, to get the desired behaviour for Last, but I think the >> > left-strict definition probably follows the conventions more. >> > >> > I originally posted this to reddit >> > (https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_maybe_too_strict/ ) >> > and was encouraged to post it here. >> > >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrew.thaddeus at gmail.com Thu May 24 13:56:48 2018 From: andrew.thaddeus at gmail.com (Andrew Martin) Date: Thu, 24 May 2018 09:56:48 -0400 Subject: Remove Semigroup and Monoid instances for Either Message-ID: The Semigroup and Monoid instances for Either have surprising behaviors. Currently, the Semigroup instance is written as: instance Semigroup (Either a b) where Left _ <> b = b a <> _ = a One would expect that the Semigroup instances for `Maybe a` and `Either () a` would have the same behaviors, but they don't. We could do better with: instance Semigroup b => Semigroup (Either a b) where (<>) = liftA2 (<>) And now the behaviors match. This generalizes the old Semigroup instance, which could be recovered with `Either a (Data.Semigroup.First b)`. For now, all I'm proposing is removing the existing Semigroup and Monoid instances for Either. I do not believe that new instances should be given immidiately, since that would be the worst kind of breaking change: one that the compiler does not error on. -Andrew Thaddeus Martin -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrew.thaddeus at gmail.com Thu May 24 14:02:01 2018 From: andrew.thaddeus at gmail.com (Andrew Martin) Date: Thu, 24 May 2018 10:02:01 -0400 Subject: Bits typeclass law for LSB Message-ID: The trac issue this is asking about is found here: https://ghc.haskell.org/trac/ghc/ticket/14839. I'm looking for any feedback from the broader community to see if the proposed law is incompatible with any important uses of Bits. The text of the trac issue is provided below: The documentation for the Bits typeclass claims: Bits are numbered from 0 with bit 0 being the least significant bit. However, there's no law specified in the typeclass that enforces this. I realized this recently because I've been adding the laws for Bits to a library of property tests I maintain: http://hackage.haskell.org/package/quickcheck-classes-0.3.3/docs/Test-QuickCheck-Classes.html#v:bitsLaws In another package of mine, someone requested to add a Bits instance for a type but with the MSB considered bit 0. ( https://github.com/andrewthad/haskell-ip/issues/29) I thought this would fail to satisfy a law of Bits, but it doesn't. So at the least, I was thinking we could add the following laws to FiniteBits: countTrailingZeros (bit 0) = 0 countLeadingZeros (bit 0) = finiteBitSize undefined - 1 -- -Andrew Thaddeus Martin -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrew.thaddeus at gmail.com Thu May 24 14:05:07 2018 From: andrew.thaddeus at gmail.com (Andrew Martin) Date: Thu, 24 May 2018 10:05:07 -0400 Subject: Strictness of Semigroup instance for Maybe In-Reply-To: References: <396F6084-317A-42E5-B5C4-9C98B437F215@doisinkidney.com> Message-ID: Ah, here it is: https://www.reddit.com/r/haskell/comments/7nmcrj/what_evaluation_strategy_to_use_for_a_new/ds3ykie/. Relevant excerpt: I often see people saying they can get away with working with a "Lazy" annotation in a strict language all the time. Strict languages with "opt-in" laziness tend to lack the courage of their conviction after making that statement, though. You can get a sense for how honest that appraisal is by looking at the definition of Monoid in their language. If you wanted to capture all of the power of a lazy language, it'd need to be marked Lazy in one or both of its arguments. If its only one then Dual gets hosed. (See many of the versions of scalaz) If neither then you dare not implement any or all via the Any or All monoid, lest you lose short-circuiting (&&) evaluation, if you have it at all. So you now have an abstraction, but dare not use it. You find that in a language that is strict, these notions like Monoid, Applicative, etc. all really need to pick up variants based on your strictness in each argument, and frankly, nobody bothers and it all gets swept under the rug. On Wed, May 23, 2018 at 7:21 AM, Andrew Martin wrote: > I feel the the way concerning being lazy as possible and being left-strict > where there is a symmetric choice to be made. This seems to be a common > theme is base, although I’ve never seen it officially endorsed. I have seen > Edward Kmett talk about this on reddit (contrasting it with the Monoid > classes in strict-by-default languages), but I cannot find the thread. > > Sent from my iPhone > > On May 22, 2018, at 7:57 PM, Tikhon Jelvis wrote: > > I think the extra laziness makes sense here—it matches the behavior of > common functions like &&. My general expectation is that functions are as > lazy as they can be and, in the case of operators with two arguments, that > evaluation goes left-to-right. (Again like &&.) > > On Tue, May 22, 2018 at 4:37 PM, David Feuer > wrote: > >> I think extra laziness here would be a bit surprising. >> >> On Tue, May 22, 2018 at 5:57 PM, Donnacha Oisín Kidney >> wrote: >> > The current semigroup instance for Maybe looks like this: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > a <> Nothing = a >> > Just a <> Just b = Just (a <> b) >> > >> > However, it could be lazier: >> > >> > instance Semigroup a => Semigroup (Maybe a) where >> > Nothing <> b = b >> > Just a <> b = Just (maybe a (a<>) b) >> > >> > This causes different behaviour for Data.Semigroup.First and >> > Data.Monoid.First: >> > >> > >>> Data.Monoid.getFirst . foldMap pure $ [1..] >> > Just 1 >> > >>> fmap Data.Semigroup.getFirst . Data.Semigroup.getOption . >> foldMap >> > (pure.pure) $ [1..] >> > _|_ >> > >> > A different definition for `Option` gets back the old behaviour: >> > >> > newtype LeftOption a = LeftOption { getLeftOption :: Maybe a } >> > >> > instance Semigroup a => Semigroup (LeftOption a) where >> > LeftOption Nothing <> ys = ys >> > LeftOption (Just x) <> LeftOption ys = LeftOption (Just (maybe x >> (x<>) >> > ys)) >> > >> > instance Semigroup a => Monoid (LeftOption a) where >> > mempty = LeftOption Nothing >> > mappend = (<>) >> > >> > >>> fmap Data.Semigroup.getFirst . getLeftOption . foldMap >> (LeftOption . >> > Just . Data.Semigroup.First) $ [1..] >> > Just 1 >> > >> > Is there any benefit to the extra strictness? Should this be changed? >> > >> > Another consideration is that the definition could equivalently be >> > right-strict, to get the desired behaviour for Last, but I think the >> > left-strict definition probably follows the conventions more. >> > >> > I originally posted this to reddit >> > (https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_ >> maybe_too_strict/) >> > and was encouraged to post it here. >> > >> > _______________________________________________ >> > Libraries mailing list >> > Libraries at haskell.org >> > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -- -Andrew Thaddeus Martin -------------- next part -------------- An HTML attachment was scrubbed... URL: From hvriedel at gmail.com Thu May 24 14:28:56 2018 From: hvriedel at gmail.com (Herbert Valerio Riedel) Date: Thu, 24 May 2018 16:28:56 +0200 Subject: Remove Semigroup and Monoid instances for Either In-Reply-To: (Andrew Martin's message of "Thu, 24 May 2018 09:56:48 -0400") References: Message-ID: <87in7di0uv.fsf@gmail.com> Andrew, On 2018-05-24 at 09:56:48 -0400, Andrew Martin wrote: > One would expect that the Semigroup instances for `Maybe a` and `Either () > a` would have the same behaviors Given this expectation is used as motivation for the proposal, could you expand the rationale from which you derive this expectation? Are there data-points that give reason to believe that the current instance are actually problematic, as they result in code being written that behaves in an unexpected way that isn't detected right-away by programmers? > For now, all I'm proposing is removing the existing Semigroup and Monoid > instances for Either. I do not believe that new instances should be given > immidiately, since that would be the worst kind of breaking change: one > that the compiler does not error on. If the intent is to re-add different instance at a later time, then I strongly oppose this IMHO wrong reasoning -- either get rid of the instances forever, or switch over gap-less We had a very similar discussion a couple months ago; I'll just refer to the argument from then which applies here as well with minor modifications, see below -------------------- Start of forwarded message -------------------- Subject: Re: Proposal: Remove Semigroup and Monoid instances for Data.Map, Data.IntMap, Data.HashMap From: Oleg Grenrus Message-ID: Date: Wed, 14 Feb 2018 17:48:36 +0200 I don't like a "no-instances" window. We can change the instances to correct ones directly. That's what semantic versioning is about, to be able to communicate semantic changes. We should go directly to    Semigroup v => Semigroup (Map k v)    Semigroup v => Monoid (Map k v) If `containers-0.6` or `containers-1.0` included some other (compile-time) breaking change: even better. I want to point out that a lot of code *will* break at compile-time with the change.  In polymorphic setting `v` doesn't have `Semigroup v` attached.  Many concrete types arent `Semigroup` (e.g. `Int`; here and later when I say isn't `Semigroup`, I mean that it isn't `Monoid` either). I tried to compile our `futurice-prelude` [1] and one small size internal app (40 modules) with patched containers: things break at compile time This change *won't get thru unnoticed*. See below for details. Also people (we and others) use `mempty` for `Map.empty`, but for `mempty` semantics won't change. We might need to use `Map.empty` if `v` isn't `Semigroup`, but that's catched by compiler. Note: that would mean to use `Map.empty` everywhere if there is no-instances window. I also conjecture, based on the results, that `Ord k => Monoid (Map k v)` for `union` is currently avoided in libs. Maybe because it does *the wrong thing*, so people don't use it. In our own 50kLOC codebase we have three `Map.unionWith` or `Map.unionsWith`, one of which is     groupThings = Map.unionsWith (<>) . map f). I think `Map k String` or `Map k Text` things might be common in private codebases (not ours). Maybe not the most popular opinion, but I think they deserve to break. Something else: If we replace the instance, we have to leave it out of `containers` for older than `base-4.9`. - Either we provide `Semigroup` (and `Monoid` !) in `semigroups` (See +) or - just have `base >= 4.9` in that release of `containers`   (that will be three GHCs soon). To conclude, The brekage on Hackage would be driven by things not having `Semigroup` instances, not semantics. There might be subtle breakages, but not something we as community cannot handle. So let's just make a change. Best regards, Oleg + At this point we want `Semigroup v` for `Monoid (Map k v)`, and because   `semigroups` depend on `containers` (and not other way), we'd need to have   `Monoid (Map k v)` also in `semigroups`. --- I did an experiment: compile our `futurice-prelude` [1] with amended `containers`, I changed only instances for `Map`. Removal of the instances breaks Cabal, so I could test far enough what happens:     Distribution/Simple/Program/GHC.hs:546:12: error:         • No instance for (Semigroup (Map Extension String))             arising from a use of ‘gmempty’         • In the expression: gmempty           In an equation for ‘mempty’: mempty = gmempty           In the instance declaration for ‘Monoid GhcOptions’         |     546 |   mempty = gmempty         |            ^^^^^^^ This is one place where we want `union` semantics. OTOH in current development version of Cabal the map is of type     Map Extension (Maybe Compiler.Flag), as we moving avoid from stringly-typed programming. And `Flag` doesn't have `Semigroup` instance. Second step: Let's see where Monoid (Map k v) is used. We cannot deprecate the instance, but we can se where it's used by a -fdefer-type-error trick (thanks Bartosz Nitka aka niteria [2]) Note that this step actually has changes from third step already, so we don't see failures where `Semigroup v` context would have caused compilation failure. To my happy surprise the instance were used only once in Cabal-2.0.1.1 (above), and then in `futurice-prelude` itself where it would also break with `Semigroup v`. So 231 packages at the bottom of dependency graph of lens+servant apps don't use `Monoid (Map k v)`. Interesting fact, I'd say. Third step: If I change instance to use `unionWith (<>)`, then the first failure in our production code is `reducers-3.12.2`     src/Data/Semigroup/Reducer.hs:233:10: error:         • Could not deduce (Semigroup v)             arising from the superclasses of an instance declaration           from the context: Ord k             bound by the instance declaration             at src/Data/Semigroup/Reducer.hs:233:10-42           Possible fix:             add (Semigroup v) to the context of the instance declaration         • In the instance declaration for ‘Reducer (k, v) (Map k v)’         |     233 | instance Ord k => Reducer (k, v) (Map k v) where and `servant-0.13`     src/Servant/Server/Internal.hs:691:34: error:         • No instance for (Data.Semigroup.Semigroup                              (Router' env RoutingApplication))             arising from a use of ‘mempty’         • In the first argument of ‘StaticRouter’, namely ‘mempty’           In the expression: StaticRouter mempty mempty           In an equation for ‘route’:               route Proxy _ _ = StaticRouter mempty mempty         |     691 |   route Proxy _ _ = StaticRouter mempty mempty and `swagger2-2.2`.  `SwaggerMonoid` differes for `Maybe`, but has default implementation in terms of `Monoid`.     src/Data/Swagger/Internal/Utils.hs:116:10: error:         • Could not deduce (Data.Semigroup.Semigroup v)             arising from a use of ‘Data.Swagger.Internal.Utils.$dmswaggerMappend’           from the context: Ord k             bound by the instance declaration             at src/Data/Swagger/Internal/Utils.hs:116:10-41           Possible fix:             add (Data.Semigroup.Semigroup v) to the context of               the instance declaration         • In the expression:             Data.Swagger.Internal.Utils.$dmswaggerMappend @Map k v           In an equation for ‘swaggerMappend’:               swaggerMappend                 = Data.Swagger.Internal.Utils.$dmswaggerMappend @Map k v           In the instance declaration for ‘SwaggerMonoid (Map k v)’         |     116 | instance Ord k => SwaggerMonoid (Map k v) And then we get to `futurice-prelude` which also fails:     src/Futurice/Prelude.hs:177:41: error:         • Could not deduce (Semigroup v) arising from a use of ‘ifolded’ Funny thing about that code, is that there we work with `Map k (Map l v)` and fold them.  For other one we want `UnionWith` and for other any semantic should be ok  (we have tests, they *will* break if I get things wrong). We also have a `Map` wrapper which also breaks loudly. Fourth step: fix above and contunue investigation where `Monoid (Map k v)` is used.  I built one internal application which pulls in even more dependencies in addition to what `futurice-prelude` already depends upon (465 deps, e.g. `amazonka`). - Two of our internal libraries use `mempty` (second one a lot). Not breaking. - One package uses a `Map` wrapper used above (for the sake of experiment I   passed the `Warning` constraint down) - The app itself uses `mempty` of `folded` on things which aren't `Semigroup`. - `yaml-0.8.28` breaks:     Data/Yaml/Parser.hs:154:13: error:         • Could not deduce (Data.Map.Internal.Warning YamlValue)             arising from a use of ‘await’   `YamlValue` doesn't have a `Semigroup` (or `Monoid`) instance. - `amazonka-core-1.5.0`: `mempty`: non silent breakage.     src/Network/AWS/Data/XML.hs:252:49: error:         • No instance for (containers-0.5.11.0:Data.Map.Internal.Warning                              Text)             arising from a use of ‘mempty’         • In the second argument of ‘Element’, namely ‘mempty’           In the first argument of ‘NodeElement’, namely             ‘(Element (name k) mempty [NodeContent v])’           In the expression:             NodeElement (Element (name k) mempty [NodeContent v])         |     252 |     node (k, v) = NodeElement (Element (name k) mempty [NodeContent v]) [1]: https://github.com/futurice/haskell-futurice-prelude [2]: https://ghc.haskell.org/trac/ghc/ticket/12014#comment:6 On 14.02.2018 01:50, Herbert Valerio Riedel wrote: > David, > >>> Alright, then let's do a little Gedankenexperiment; what if you release >>> a containers-0.9.0.0 (which drops the instances) and a >>> containers-1.0.0.0 (which 'adds back' the desired new instances) on the >>> same day! >>> >>> ...wouldn't this allow us to have the cake and eat it too? ;-) >> It would let us have some cake. Users would be able to test against >> 0.9, in theory. But they'd have to do it intentionally. > This is what I was trying to get at: that's always the case. It doesn't > matter whether you release it same day, a week later, or a year later. I > have to intentionally *not* skip the 0.9 release. In fact, I'd want to > skip the 0.9 release myself if possible, as supporting both, > containers-0.9 and containers-1.0 in the same consumer code is going to > be awkward enough for me not wanting to do that (or I'd have to > basically not use the instances at all); If I care about the new > instances, I'd rather specify `containers ^>= 1.0.0.0` and thus not > support containers-0.9. > > I would have proceeded to point out in my Gedankenexperiment, that in > order to use such a container-0.9 release, you'd have to force every > package that depends on `containers` to go through such a 0.9 phase in > lockstep, which in itself poses an ordeal in terms of package update > logistic; and then if you spread the time between the 0.9 and the 1.0 > release apart, repeat this dance a 2nd time, with yet another new major > version bump, which requires yet another round of consumer-code reviews > (*because* a major version increment was signalled; and we do that as > API consumers are supposed to pay attention to the major version > increment signal...) > > So consequently, if anything, a container-0.9 release would be a kind of > an artificial pseudo-release anyway IMO. You could even just condense it > into a cabal package flag of a containers-1.0 release, which disables > the Monoid/Semigroup instances; then you don't even need a distinct > container-0.9 release at all, nor do you have to contaminate the API > progression with an artificial container-0.9 discontinuity. > >> And Stack-based projects would probably need some shenanigans to deal >> with a version of containers that doesn't come with GHC. > I'm not convinced we should let the weakest link hold us back. If > there's limitations in the tooling, we should rather address them, rather > than contort ourselves; c.f. the Genius Tailor > ( http://www.wealthculture.cn/infoShow.asp?nid=880&sort=Article%20List ) > >> So I really think that avoiding these subtle bugs requires at least a >> full GHC release cycle. > I don't think waiting a full GHC release would be either necessary nor > effective at addressing your concerns, which I consider to be disputable > arguments to begin with. > > -- hvr -------------------- End of forwarded message -------------------- From andrew.thaddeus at gmail.com Thu May 24 14:48:40 2018 From: andrew.thaddeus at gmail.com (Andrew Martin) Date: Thu, 24 May 2018 10:48:40 -0400 Subject: Remove Semigroup and Monoid instances for Either In-Reply-To: <87in7di0uv.fsf@gmail.com> References: <87in7di0uv.fsf@gmail.com> Message-ID: There's a project at work that a colleague and I worked on where we both assumed that the Monoid instance for Either would behave like the one I proposed, and then it didn't. There's also someone on reddit ( https://www.reddit.com/r/haskell/comments/8lbzan/semigroup_maybe_too_strict/dzhwzjs/) would wrote: > There is a bug somewhere anyway as instances for Either () a and Maybe a really should match, but I'm no longer sure that the bug is in the Maybe instance rather than the Either () a one. Those are my two data points. It's small, but I wanted to gauge what others thought. I'm familiar with the discussion around the Semigroup/Monoid instance for Map. There was no general consensus on whether or not there should be a gap, and I fall pretty strongly on the other side of the fence for reasons that are listed elsewhere in that thread. In the case of the Semigroup/Monoid instances for Either, I don't really care as much since the current instances have such little utility that I've never even seen anyone use them in the wild. On Thu, May 24, 2018 at 10:28 AM, Herbert Valerio Riedel wrote: > Andrew, > > On 2018-05-24 at 09:56:48 -0400, Andrew Martin wrote: > > One would expect that the Semigroup instances for `Maybe a` and `Either > () > > a` would have the same behaviors > > Given this expectation is used as motivation for the proposal, could you > expand the rationale from which you derive this expectation? Are there > data-points that give reason to believe that the current instance are > actually problematic, as they result in code being written that behaves > in an unexpected way that isn't detected right-away by programmers? > > > > For now, all I'm proposing is removing the existing Semigroup and Monoid > > instances for Either. I do not believe that new instances should be given > > immidiately, since that would be the worst kind of breaking change: one > > that the compiler does not error on. > > If the intent is to re-add different instance at a later time, then I > strongly oppose this IMHO wrong reasoning -- either get rid of the > instances forever, or switch over gap-less > > We had a very similar discussion a couple months ago; I'll just refer > to the argument from then which applies here as well with minor > modifications, see below > > > -------------------- Start of forwarded message -------------------- > Subject: Re: Proposal: Remove Semigroup and Monoid instances for > Data.Map, Data.IntMap, Data.HashMap > From: Oleg Grenrus > Message-ID: > Date: Wed, 14 Feb 2018 17:48:36 +0200 > > I don't like a "no-instances" window. We can change the instances to > correct > ones directly. That's what semantic versioning is about, to be able to > communicate semantic changes. > > We should go directly to > > Semigroup v => Semigroup (Map k v) > Semigroup v => Monoid (Map k v) > > If `containers-0.6` or `containers-1.0` included some other (compile-time) > breaking change: even better. > > I want to point out that a lot of code *will* break at compile-time with > the > change. In polymorphic setting `v` doesn't have `Semigroup v` > attached. Many > concrete types arent `Semigroup` (e.g. `Int`; here and later when I say > isn't > `Semigroup`, I mean that it isn't `Monoid` either). > > I tried to compile our `futurice-prelude` [1] and one small size internal > app (40 modules) with patched containers: things break at compile time > > This change *won't get thru unnoticed*. See below for details. > > Also people (we and others) use `mempty` for `Map.empty`, but for `mempty` > semantics won't change. We might need to use `Map.empty` if `v` isn't > `Semigroup`, > but that's catched by compiler. Note: that would mean to use `Map.empty` > everywhere > if there is no-instances window. > > I also conjecture, based on the results, that `Ord k => Monoid (Map k > v)` for > `union` is currently avoided in libs. Maybe because it does *the wrong > thing*, > so people don't use it. In our own 50kLOC codebase we have three > `Map.unionWith` or `Map.unionsWith`, one of which is > > groupThings = Map.unionsWith (<>) . map f). > > I think `Map k String` or `Map k Text` things might be common in private > codebases (not ours). Maybe not the most popular opinion, but I think they > deserve to break. > > > Something else: If we replace the instance, we have to leave it out of > `containers` for older than `base-4.9`. > - Either we provide `Semigroup` (and `Monoid` !) in `semigroups` (See +) or > - just have `base >= 4.9` in that release of `containers` > (that will be three GHCs soon). > > > To conclude, The brekage on Hackage would be driven by things not having > `Semigroup` instances, not semantics. There might be subtle breakages, > but not > something we as community cannot handle. So let's just make a change. > > Best regards, Oleg > > + At this point we want `Semigroup v` for `Monoid (Map k v)`, and because > `semigroups` depend on `containers` (and not other way), we'd need to > have > `Monoid (Map k v)` also in `semigroups`. > > --- > > I did an experiment: compile our `futurice-prelude` [1] with amended > `containers`, I changed only instances for `Map`. > > > Removal of the instances breaks Cabal, so I could test far enough what > happens: > > Distribution/Simple/Program/GHC.hs:546:12: error: > • No instance for (Semigroup (Map Extension String)) > arising from a use of ‘gmempty’ > • In the expression: gmempty > In an equation for ‘mempty’: mempty = gmempty > In the instance declaration for ‘Monoid GhcOptions’ > | > 546 | mempty = gmempty > | ^^^^^^^ > > This is one place where we want `union` semantics. > OTOH in current development version of Cabal the map is of type > > Map Extension (Maybe Compiler.Flag), > > as we moving avoid from stringly-typed programming. And `Flag` doesn't have > `Semigroup` instance. > > > Second step: Let's see where Monoid (Map k v) is used. We cannot > deprecate the > instance, but we can se where it's used by a -fdefer-type-error trick > (thanks Bartosz Nitka aka niteria [2]) > Note that this step actually has changes from third step already, so > we don't see failures where `Semigroup v` context would have caused > compilation > failure. > > To my happy surprise the instance were used only once in Cabal-2.0.1.1 > (above), > and then in `futurice-prelude` itself where it would also break with > `Semigroup v`. > So 231 packages at the bottom of dependency graph of lens+servant apps > don't use `Monoid (Map k v)`. Interesting fact, I'd say. > > > Third step: If I change instance to use `unionWith (<>)`, then the first > failure in our production code is `reducers-3.12.2` > > src/Data/Semigroup/Reducer.hs:233:10: error: > • Could not deduce (Semigroup v) > arising from the superclasses of an instance declaration > from the context: Ord k > bound by the instance declaration > at src/Data/Semigroup/Reducer.hs:233:10-42 > Possible fix: > add (Semigroup v) to the context of the instance declaration > • In the instance declaration for ‘Reducer (k, v) (Map k v)’ > | > 233 | instance Ord k => Reducer (k, v) (Map k v) where > > and `servant-0.13` > > src/Servant/Server/Internal.hs:691:34: error: > • No instance for (Data.Semigroup.Semigroup > (Router' env RoutingApplication)) > arising from a use of ‘mempty’ > • In the first argument of ‘StaticRouter’, namely ‘mempty’ > In the expression: StaticRouter mempty mempty > In an equation for ‘route’: > route Proxy _ _ = StaticRouter mempty mempty > | > 691 | route Proxy _ _ = StaticRouter mempty mempty > > and `swagger2-2.2`. `SwaggerMonoid` differes for `Maybe`, but has default > implementation in terms of `Monoid`. > > src/Data/Swagger/Internal/Utils.hs:116:10: error: > • Could not deduce (Data.Semigroup.Semigroup v) > arising from a use of > ‘Data.Swagger.Internal.Utils.$dmswaggerMappend’ > from the context: Ord k > bound by the instance declaration > at src/Data/Swagger/Internal/Utils.hs:116:10-41 > Possible fix: > add (Data.Semigroup.Semigroup v) to the context of > the instance declaration > • In the expression: > Data.Swagger.Internal.Utils.$dmswaggerMappend @Map k v > In an equation for ‘swaggerMappend’: > swaggerMappend > = Data.Swagger.Internal.Utils.$dmswaggerMappend @Map k v > In the instance declaration for ‘SwaggerMonoid (Map k v)’ > | > 116 | instance Ord k => SwaggerMonoid (Map k v) > > And then we get to `futurice-prelude` which also fails: > > src/Futurice/Prelude.hs:177:41: error: > • Could not deduce (Semigroup v) arising from a use of ‘ifolded’ > > Funny thing about that code, is that there we work with `Map k (Map l > v)` and > fold them. For other one we want `UnionWith` and for other any semantic > should > be ok (we have tests, they *will* break if I get things wrong). > > We also have a `Map` wrapper which also breaks loudly. > > > Fourth step: fix above and contunue investigation where `Monoid (Map k > v)` is > used. I built one internal application which pulls in even more > dependencies > in addition to what `futurice-prelude` already depends upon (465 deps, e.g. > `amazonka`). > > - Two of our internal libraries use `mempty` (second one a lot). Not > breaking. > > - One package uses a `Map` wrapper used above (for the sake of experiment I > passed the `Warning` constraint down) > > - The app itself uses `mempty` of `folded` on things which aren't > `Semigroup`. > > - `yaml-0.8.28` breaks: > > Data/Yaml/Parser.hs:154:13: error: > • Could not deduce (Data.Map.Internal.Warning YamlValue) > arising from a use of ‘await’ > > `YamlValue` doesn't have a `Semigroup` (or `Monoid`) instance. > > - `amazonka-core-1.5.0`: `mempty`: non silent breakage. > > src/Network/AWS/Data/XML.hs:252:49: error: > • No instance for (containers-0.5.11.0:Data.Map.Internal.Warning > Text) > arising from a use of ‘mempty’ > • In the second argument of ‘Element’, namely ‘mempty’ > In the first argument of ‘NodeElement’, namely > ‘(Element (name k) mempty [NodeContent v])’ > In the expression: > NodeElement (Element (name k) mempty [NodeContent v]) > | > 252 | node (k, v) = NodeElement (Element (name k) mempty > [NodeContent v]) > > > [1]: https://github.com/futurice/haskell-futurice-prelude > [2]: https://ghc.haskell.org/trac/ghc/ticket/12014#comment:6 > > > On 14.02.2018 01:50, Herbert Valerio Riedel wrote: > > David, > > > >>> Alright, then let's do a little Gedankenexperiment; what if you release > >>> a containers-0.9.0.0 (which drops the instances) and a > >>> containers-1.0.0.0 (which 'adds back' the desired new instances) on the > >>> same day! > >>> > >>> ...wouldn't this allow us to have the cake and eat it too? ;-) > >> It would let us have some cake. Users would be able to test against > >> 0.9, in theory. But they'd have to do it intentionally. > > This is what I was trying to get at: that's always the case. It doesn't > > matter whether you release it same day, a week later, or a year later. I > > have to intentionally *not* skip the 0.9 release. In fact, I'd want to > > skip the 0.9 release myself if possible, as supporting both, > > containers-0.9 and containers-1.0 in the same consumer code is going to > > be awkward enough for me not wanting to do that (or I'd have to > > basically not use the instances at all); If I care about the new > > instances, I'd rather specify `containers ^>= 1.0.0.0` and thus not > > support containers-0.9. > > > > I would have proceeded to point out in my Gedankenexperiment, that in > > order to use such a container-0.9 release, you'd have to force every > > package that depends on `containers` to go through such a 0.9 phase in > > lockstep, which in itself poses an ordeal in terms of package update > > logistic; and then if you spread the time between the 0.9 and the 1.0 > > release apart, repeat this dance a 2nd time, with yet another new major > > version bump, which requires yet another round of consumer-code reviews > > (*because* a major version increment was signalled; and we do that as > > API consumers are supposed to pay attention to the major version > > increment signal...) > > > > So consequently, if anything, a container-0.9 release would be a kind of > > an artificial pseudo-release anyway IMO. You could even just condense it > > into a cabal package flag of a containers-1.0 release, which disables > > the Monoid/Semigroup instances; then you don't even need a distinct > > container-0.9 release at all, nor do you have to contaminate the API > > progression with an artificial container-0.9 discontinuity. > > > >> And Stack-based projects would probably need some shenanigans to deal > >> with a version of containers that doesn't come with GHC. > > I'm not convinced we should let the weakest link hold us back. If > > there's limitations in the tooling, we should rather address them, rather > > than contort ourselves; c.f. the Genius Tailor > > ( http://www.wealthculture.cn/infoShow.asp?nid=880&sort=Article%20List ) > > > >> So I really think that avoiding these subtle bugs requires at least a > >> full GHC release cycle. > > I don't think waiting a full GHC release would be either necessary nor > > effective at addressing your concerns, which I consider to be disputable > > arguments to begin with. > > > > -- hvr > -------------------- End of forwarded message -------------------- > -- -Andrew Thaddeus Martin -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.feuer at gmail.com Fri May 25 05:45:46 2018 From: david.feuer at gmail.com (David Feuer) Date: Fri, 25 May 2018 01:45:46 -0400 Subject: Help evaluating TQueue variants Message-ID: I've written three related variations on TQueue (from the stm package). All three are designed to avoid the reader starvation problem described in GHC Trac 9539 [1] while limiting contention. Two are based on Okasaki's scheduled (i.e., real-time) banker's queues, while the third is based on his amortized-time banker's queue. I am hoping one or more people with programs that use TQueue heavily would be willing and able to try out these alternatives and see how they perform in their applications. I'm interested in how they compare to the current TQueue implementation, and also how they compare to each other. The queues are currently in a GitHub repository [2], but if it would be helpful I could put them up on Hackage. Thank you for your time. [1] https://ghc.haskell.org/trac/ghc/ticket/9539 [2] https://github.com/treeowl/stm-queues From chessai1996 at gmail.com Tue May 29 18:27:43 2018 From: chessai1996 at gmail.com (Daniel Cartwright) Date: Tue, 29 May 2018 14:27:43 -0400 Subject: CComplex type Message-ID: I have recently found it useful while working with the FFI to have a CComplex data type, like so: data CComplex a = Complex {-# UNPACK #-} !a {-# UNPACK #-} !a Would something like this be a good addition to Foreign.C.Types? -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed May 30 17:49:29 2018 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Wed, 30 May 2018 13:49:29 -0400 Subject: CComplex type In-Reply-To: References: Message-ID: More broadly: the FFI types ghc has should be revamped to add not just that but also the StdInt types like (U)Int_{Ptr,64,32} etc but yes, thats definitely specfied in like c99 or c11, and should be in the ffi addendum etc all of the above should also be reflected in the 2020 haskell revision. Ostensibly John Wiegley volunteered for that, but if you wanna lead the charge on that, i'm pretty confident he'd be happy to let you. I'm "cosponsoring" that too, so any way i can help let me know :) On Tue, May 29, 2018 at 2:27 PM, Daniel Cartwright wrote: > I have recently found it useful while working with the FFI to have a > CComplex data type, like so: > > data CComplex a = Complex {-# UNPACK #-} !a {-# UNPACK #-} !a > > Would something like this be a good addition to Foreign.C.Types? > > _______________________________________________ > Libraries mailing list > Libraries at haskell.org > http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chessai1996 at gmail.com Wed May 30 17:54:53 2018 From: chessai1996 at gmail.com (Daniel Cartwright) Date: Wed, 30 May 2018 13:54:53 -0400 Subject: CComplex type In-Reply-To: References: Message-ID: Yes, there should be a lot more in the C FFI. I would definitely be interested in working on that. On Wed, May 30, 2018 at 1:49 PM, Carter Schonwald < carter.schonwald at gmail.com> wrote: > More broadly: the FFI types ghc has should be revamped to add not just > that but also the StdInt types like (U)Int_{Ptr,64,32} etc > > but yes, thats definitely specfied in like c99 or c11, and should be in > the ffi addendum etc > > all of the above should also be reflected in the 2020 haskell revision. > > Ostensibly John Wiegley volunteered for that, but if you wanna lead the > charge on that, i'm pretty confident he'd be happy to let you. I'm > "cosponsoring" that too, so any way i can help let me know :) > > > On Tue, May 29, 2018 at 2:27 PM, Daniel Cartwright > wrote: > >> I have recently found it useful while working with the FFI to have a >> CComplex data type, like so: >> >> data CComplex a = Complex {-# UNPACK #-} !a {-# UNPACK #-} !a >> >> Would something like this be a good addition to Foreign.C.Types? >> >> _______________________________________________ >> Libraries mailing list >> Libraries at haskell.org >> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed May 30 18:54:52 2018 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Wed, 30 May 2018 14:54:52 -0400 Subject: ANN: primitive 0.6.4.0 Message-ID: This is a pretty exciting (albeit minor version) I'd like to especially thank David Feuer (treeowl ) and Andrew Martin (andrewthad) for their contributions the change log has a huge number of bug fixes relative to 0.6.2-3 also we added some new modules of features PrimArray --- unboxed nonsliceable vectors MVar -- Mvars that run in any PrimMonad augmented the Data.Primitive exports for increased consistency (the new .Ptr and .Mvar modules aren't exported in this minor version so users can easily migrate) Changes in version 0.6.4.0 - Introduce Data.Primitive.PrimArray, which offers types and function for dealing with a ByteArray tagged with a phantom type variable for tracking the element type. - Implement isByteArrayPinned and isMutableByteArrayPinned. - Add Eq1, Ord1, Show1, and Read1 instances for Array and SmallArray. - Improve the test suite. This includes having property tests for typeclasses from base such as Eq, Ord, Functor, Applicative, Monad, IsList, Monoid, Foldable, and Traversable. - Fix the broken IsList instance for ByteArray. The old definition would allocate a byte array of the correct size and then leave the memory unitialized instead of writing the list elements to it. - Fix the broken Functor instance for Array. The old definition would allocate an array of the correct size with thunks for erroring installed at every index. It failed to replace these thunks with the result of the function applied to the elements of the argument array. - Fix the broken Applicative instances of Array and SmallArray. The old implementation of <*> for Arrayfailed to initialize some elements but correctly initialized others in the resulting Array. It is unclear what the old behavior of <*> was for SmallArray, but it was incorrect. - Fix the broken Monad instances for Array and SmallArray. - Fix the implementation of foldl1 in the Foldable instances for Array and SmallArray. In both cases, the old implementation simply returned the first element of the array and made no use of the other elements in the array. - Fix the implementation of mconcat in the Monoid instance for SmallArray. - Implement Data.Primitive.Ptr, implementations of Ptr functions that require a Prim constraint instead of a Storable constraint. - Add PrimUnlifted instances for TVar and MVar. - Use compareByteArrays# for the Eq and Ord instances of ByteArray when building with GHC 8.4 and newer. - Add Prim instances for lots of types in Foreign.C.Types and System.Posix.Types. - Reexport Data.Primitive.SmallArray and Data.Primitive.UnliftedArray from Data.Primitive. - Add fold functions and map function to Data.Primitive.UnliftedArray. Add typeclass instances for IsList, Ord, and Show. - Add defaultSetByteArray# and defaultSetOffAddr# to Data.Primitive.Types. -------------- next part -------------- An HTML attachment was scrubbed... URL: From drkoster at qq.com Wed May 30 20:19:23 2018 From: drkoster at qq.com (=?gb18030?B?RHIuS29zdGVy?=) Date: Thu, 31 May 2018 04:19:23 +0800 Subject: [Haskell-cafe] ANN: primitive 0.6.4.0 Message-ID: I have make some comments on reddit, but still I want to record them here: After reading the new code, I got a feeling that there're some API lacking considerations. Here is some of my personal concerns: The generalized MVar is basically useless because ST is meant to seal its state token, you won't want to add a forkST. You can argue that the atomic operations on MutVar is already added, but still I want to justify its usefulness. There're too much combinators added to PrimArray, is there a plan to port these to other arrays? If we ever provide toList operations, then I would really want it to be a good producer in base's fold-build fusion' view, it's robust and easy to implement, and folding is basically the same speed with List.fold and toList. Anyway it seems I missed the bike shedding, but still I want to thank for all the efforts, I'll try to follow new GitHub workflow more closely. Cheers Winter 发自我的iPhone ------------------ Original ------------------ From: Carter Schonwald Date: Thu,May 31,2018 2:55 AM To: haskell-cafe , Haskell Libraries Subject: Re: [Haskell-cafe] ANN: primitive 0.6.4.0 This is a pretty exciting (albeit minor version) I'd like to especially thank David Feuer (treeowl ) and Andrew Martin (andrewthad) for their contributions the change log has a huge number of bug fixes relative to 0.6.2-3 also we added some new modules of features PrimArray --- unboxed nonsliceable vectors MVar -- Mvars that run in any PrimMonad augmented the Data.Primitive exports for increased consistency (the new .Ptr and .Mvar modules aren't exported in this minor version so users can easily migrate) Changes in version 0.6.4.0 Introduce Data.Primitive.PrimArray, which offers types and function for dealing with a ByteArray tagged with a phantom type variable for tracking the element type. Implement isByteArrayPinned and isMutableByteArrayPinned. Add Eq1, Ord1, Show1, and Read1 instances for Array and SmallArray. Improve the test suite. This includes having property tests for typeclasses from base such as Eq, Ord, Functor, Applicative, Monad, IsList, Monoid, Foldable, and Traversable. Fix the broken IsList instance for ByteArray. The old definition would allocate a byte array of the correct size and then leave the memory unitialized instead of writing the list elements to it. Fix the broken Functor instance for Array. The old definition would allocate an array of the correct size with thunks for erroring installed at every index. It failed to replace these thunks with the result of the function applied to the elements of the argument array. Fix the broken Applicative instances of Array and SmallArray. The old implementation of <*> for Arrayfailed to initialize some elements but correctly initialized others in the resulting Array. It is unclear what the old behavior of <*> was for SmallArray, but it was incorrect. Fix the broken Monad instances for Array and SmallArray. Fix the implementation of foldl1 in the Foldable instances for Array and SmallArray. In both cases, the old implementation simply returned the first element of the array and made no use of the other elements in the array. Fix the implementation of mconcat in the Monoid instance for SmallArray. Implement Data.Primitive.Ptr, implementations of Ptr functions that require a Prim constraint instead of a Storable constraint. Add PrimUnlifted instances for TVar and MVar. Use compareByteArrays# for the Eq and Ord instances of ByteArray when building with GHC 8.4 and newer. Add Prim instances for lots of types in Foreign.C.Types and System.Posix.Types. Reexport Data.Primitive.SmallArray and Data.Primitive.UnliftedArray from Data.Primitive. Add fold functions and map function to Data.Primitive.UnliftedArray. Add typeclass instances for IsList, Ord, and Show. Add defaultSetByteArray# and defaultSetOffAddr# to Data.Primitive.Types. -------------- next part -------------- An HTML attachment was scrubbed... URL: From carter.schonwald at gmail.com Wed May 30 20:53:29 2018 From: carter.schonwald at gmail.com (Carter Schonwald) Date: Wed, 30 May 2018 16:53:29 -0400 Subject: [Haskell-cafe] ANN: primitive 0.6.4.0 In-Reply-To: References: Message-ID: I think your feedback makes perfect sense (to repeat what i said on reddit) for *MVar*: this was an addition Dan Doel and I discussed some years ago but never quite got to. The context is 1) its totally well behaved (though in isolation theres indeed a valid argument for MutVar instead) 2) it means theres some off the shelf substrate for userland / library land experimentation with approaches to deterministic parallism/concurrency (a la the LVar package or the like) 3) more tools for writing mutable thread safe data structures which may have both pure and mutable interfaces. as for *PrimArray* having more operations than the analogous Array and SmallArray, that was definitely an oversight. Its one of those things thats obvious once its said, but easy to lose track of if no one points it out when lost in the weeds as for lists/fusion, your points make perfect sense. please feel welcome to chip in on infrastructure/code review when you deem it worthwhile! Ryan and myself are definitely spread thin with our various other focii, and i'm told many collaborating hands make light work (ideally :) ) many thanks :) -Carter On Wed, May 30, 2018 at 4:19 PM, Dr.Koster wrote: > I have make some comments on reddit, but still I want to record them here: > After reading the new code, I got a feeling that there're some API lacking > considerations. Here is some of my personal concerns: > > 1. > > The generalized MVar is basically useless because ST is meant to seal > its state token, you won't want to add a forkST. You can argue that the > atomic operations on MutVar is already added, but still I want to justify > its usefulness. > 2. > > There're too much combinators added to PrimArray, is there a plan to > port these to other arrays? > 3. > > If we ever provide toList operations, then I would really want it to > be a good producer in base's fold-build fusion' view, it's robust and easy > to implement, and folding is basically the same speed with List.fold and > toList. > > Anyway it seems I missed the bike shedding, but still I want to thank for > all the efforts, I'll try to follow new GitHub workflow more closely. > Cheers > Winter > 发自我的iPhone > > > ------------------ Original ------------------ > *From:* Carter Schonwald > *Date:* Thu,May 31,2018 2:55 AM > *To:* haskell-cafe , Haskell Libraries < > libraries at haskell.org> > *Subject:* Re: [Haskell-cafe] ANN: primitive 0.6.4.0 > > This is a pretty exciting (albeit minor version) > > I'd like to especially thank David Feuer (treeowl ) and Andrew Martin > (andrewthad) for their contributions > > the change log has a huge number of bug fixes relative to 0.6.2-3 > > also we added some new modules of features > > PrimArray --- unboxed nonsliceable vectors > MVar -- Mvars that run in any PrimMonad > > augmented the Data.Primitive exports for increased consistency > (the new .Ptr and .Mvar modules aren't exported in this minor version so > users can easily migrate) > > Changes in version 0.6.4.0 > > - > > Introduce Data.Primitive.PrimArray, which offers types and function > for dealing with a ByteArray tagged with a phantom type variable for > tracking the element type. > - > > Implement isByteArrayPinned and isMutableByteArrayPinned. > - > > Add Eq1, Ord1, Show1, and Read1 instances for Array and SmallArray. > - > > Improve the test suite. This includes having property tests for > typeclasses from base such as Eq, Ord, Functor, Applicative, Monad, > IsList, Monoid, Foldable, and Traversable. > - > > Fix the broken IsList instance for ByteArray. The old definition would > allocate a byte array of the correct size and then leave the memory > unitialized instead of writing the list elements to it. > - > > Fix the broken Functor instance for Array. The old definition would > allocate an array of the correct size with thunks for erroring installed at > every index. It failed to replace these thunks with the result of the > function applied to the elements of the argument array. > - > > Fix the broken Applicative instances of Array and SmallArray. The old > implementation of <*> for Arrayfailed to initialize some elements but > correctly initialized others in the resulting Array. It is unclear > what the old behavior of <*> was for SmallArray, but it was incorrect. > - > > Fix the broken Monad instances for Array and SmallArray. > - > > Fix the implementation of foldl1 in the Foldable instances for Array > and SmallArray. In both cases, the old implementation simply returned > the first element of the array and made no use of the other elements in the > array. > - > > Fix the implementation of mconcat in the Monoid instance for SmallArray > . > - > > Implement Data.Primitive.Ptr, implementations of Ptr functions that > require a Prim constraint instead of a Storable constraint. > - > > Add PrimUnlifted instances for TVar and MVar. > - > > Use compareByteArrays# for the Eq and Ord instances of ByteArray when > building with GHC 8.4 and newer. > - > > Add Prim instances for lots of types in Foreign.C.Types and System. > Posix.Types. > - > > Reexport Data.Primitive.SmallArray and Data.Primitive.UnliftedArray > from Data.Primitive. > - > > Add fold functions and map function to Data.Primitive.UnliftedArray. > Add typeclass instances for IsList, Ord, and Show. > - > > Add defaultSetByteArray# and defaultSetOffAddr# to Data.Primitive.Types > . > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From andrew.thaddeus at gmail.com Thu May 31 00:03:59 2018 From: andrew.thaddeus at gmail.com (Andrew Martin) Date: Wed, 30 May 2018 20:03:59 -0400 Subject: [Haskell-cafe] ANN: primitive 0.6.4.0 In-Reply-To: References: Message-ID: <26A9C8F4-174A-402C-AAD2-ED772CECF909@gmail.com> Thanks for the feedback. Also, thanks for the giant PR you made a year ago. Several of the things I implemented in this release were just things I ripped out of it and put into smaller PRs. To address your questions: - There are more combinators in PrimArray than there are in the other modules. This is an inconsistency in the library design. We need to come up with a policy for what combinators are accepted. It’s weird to have a Foldable instance for Array but not get access to foldl’ and foldr for PrimArray and UnliftedArray. Similarly, functions for mapping and travsersing seem reasonable just so that you have access to the same interface if you switch from using Array to one of the other array types that isn’t fully polymorphic in its element type. I’ve considered removing some of the functions (like replicatePrimArray) in a future release. The maintainers of primitive don’t all share the same view on what exactly should be there, so we probably need to come up with a policy around this. - We should definitely have toList be a good producer. This has been discussed in other PRs. A PR for this would be accepted. - The generalized MVar is basically useless without unsafely extending it (ie forkST). But, everything provided is 100% deterministic. You have to write forkST on your own and take on the burden of proving that you use it in a way that results in deterministic behavior. I have written a package that implements a parallel variant of mergesort that needs this kind of this. I think there’s something Carter wanted to do with this as well. Sent from my iPhone > On May 30, 2018, at 4:19 PM, Dr.Koster wrote: > > I have make some comments on reddit, but still I want to record them here: > After reading the new code, I got a feeling that there're some API lacking considerations. Here is some of my personal concerns: > The generalized MVar is basically useless because ST is meant to seal its state token, you won't want to add a forkST. You can argue that the atomic operations on MutVar is already added, but still I want to justify its usefulness. > > There're too much combinators added to PrimArray, is there a plan to port these to other arrays? > > If we ever provide toList operations, then I would really want it to be a good producer in base's fold-build fusion' view, it's robust and easy to implement, and folding is basically the same speed with List.fold and toList. > > Anyway it seems I missed the bike shedding, but still I want to thank for all the efforts, I'll try to follow new GitHub workflow more closely. > > Cheers > Winter > 发自我的iPhone > > > ------------------ Original ------------------ > From: Carter Schonwald > Date: Thu,May 31,2018 2:55 AM > To: haskell-cafe , Haskell Libraries > Subject: Re: [Haskell-cafe] ANN: primitive 0.6.4.0 > > This is a pretty exciting (albeit minor version) > > I'd like to especially thank David Feuer (treeowl ) and Andrew Martin (andrewthad) for their contributions > > the change log has a huge number of bug fixes relative to 0.6.2-3 > > also we added some new modules of features > > PrimArray --- unboxed nonsliceable vectors > MVar -- Mvars that run in any PrimMonad > > augmented the Data.Primitive exports for increased consistency > (the new .Ptr and .Mvar modules aren't exported in this minor version so users can easily migrate) > > Changes in version 0.6.4.0 > > Introduce Data.Primitive.PrimArray, which offers types and function for dealing with a ByteArray tagged with a phantom type variable for tracking the element type. > > Implement isByteArrayPinned and isMutableByteArrayPinned. > > Add Eq1, Ord1, Show1, and Read1 instances for Array and SmallArray. > > Improve the test suite. This includes having property tests for typeclasses from base such as Eq, Ord, Functor, Applicative, Monad, IsList, Monoid, Foldable, and Traversable. > > Fix the broken IsList instance for ByteArray. The old definition would allocate a byte array of the correct size and then leave the memory unitialized instead of writing the list elements to it. > > Fix the broken Functor instance for Array. The old definition would allocate an array of the correct size with thunks for erroring installed at every index. It failed to replace these thunks with the result of the function applied to the elements of the argument array. > > Fix the broken Applicative instances of Array and SmallArray. The old implementation of <*> for Arrayfailed to initialize some elements but correctly initialized others in the resulting Array. It is unclear what the old behavior of <*> was for SmallArray, but it was incorrect. > > Fix the broken Monad instances for Array and SmallArray. > > Fix the implementation of foldl1 in the Foldable instances for Array and SmallArray. In both cases, the old implementation simply returned the first element of the array and made no use of the other elements in the array. > > Fix the implementation of mconcat in the Monoid instance for SmallArray. > > Implement Data.Primitive.Ptr, implementations of Ptr functions that require a Prim constraint instead of a Storable constraint. > > Add PrimUnlifted instances for TVar and MVar. > > Use compareByteArrays# for the Eq and Ord instances of ByteArray when building with GHC 8.4 and newer. > > Add Prim instances for lots of types in Foreign.C.Types and System.Posix.Types. > > Reexport Data.Primitive.SmallArray and Data.Primitive.UnliftedArray from Data.Primitive. > > Add fold functions and map function to Data.Primitive.UnliftedArray. Add typeclass instances for IsList, Ord, and Show. > > Add defaultSetByteArray# and defaultSetOffAddr# to Data.Primitive.Types. > > > _______________________________________________ > Haskell-Cafe mailing list > To (un)subscribe, modify options or view archives go to: > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe > Only members subscribed via the mailman list are allowed to post. -------------- next part -------------- An HTML attachment was scrubbed... URL: From chessai1996 at gmail.com Thu May 31 16:43:04 2018 From: chessai1996 at gmail.com (Daniel Cartwright) Date: Thu, 31 May 2018 12:43:04 -0400 Subject: Package take over: eigen Message-ID: Hi all, I tried to contact Oleg Sidorkin who is the sole maintainer of eigen (https://hackage.haskell.org/package/eigen) at the stated email address (oleg dot sidorkin at gmail dot com), but received no repsonse. I also opened a GitHub issue at https://github.com/osidorkin/haskell-eigen/issues/17, asking to be a comaintainer for this package, and received no response. Furthermore, this Oleg seems to be mostly inactive on GitHub, with only two contributions over the last 12 months, the most recent one being in November of 2017. The last version of eigen was uploaded "by OlegSidorkin at Tue Nov 7 05:53:55 UTC 2017". The haskell bindings to eigen are currently using a deprecated version of the eigen library. I have done work at the following fork: https://github.com/haskell-numerical/eigen, where I have gotten the bindings up-to-date with the most recent stable version of eigen, as well as incorporating some changes brought up by users of the library in the issue tracker and PRs of Oleg Sidorkin's GitHub repo. I'd like to become (co-)maintainer of eigen. I have a strong interest in maintaining as well as using this library. -------------- next part -------------- An HTML attachment was scrubbed... URL: