Adding Fixed Point Data Types to base

I would like to propose export Fix, Free, and Cofree from a new module in base (maybe something like Data.Functor.Recursion, the name is unimportant). The definitions of Free and Cofree would be as there are in the `free` package in Control.Monad.Free and Control.Monad.Cofree. The `free` package would then reexport these types in their respective modules rather than redefining them. All of the other utilities functions from these packages would not be moved to `base`; they would remain in `free`. Fix would be defined as: newtype Fix f = Fix { unFix :: f (Fix f) } The advantage this offers is that Free and Cofree would be able to enjoy a greater number of typeclass instances provided libraries across the ecosystem. As it stands, adding the somewhat heavy `free` dependency is not a good choice for libraries like `aeson`, `mustache`, and `hashable`. In the case of Fix, the ecosystem currently lacks a canonical library that provides it (recursion-schemes and data-fix both offer the same definition though, and various tutorials all define it the same way). It could benefit from the new instances as well. The disadvantage is the usual disadvantage: Adding any data type to base is a future commitment to that data type, and compile times for base go up a little, and there is work to be done to move it into base to begin with. I would gladly help with any of the work that needs to be done to make this happen. I believe that Fix and Free (and Cofree to a lesser extent) have proved themselves over years of use in the ecosystem. I would appreciate any feedback or thoughts that others have on this topic. Thanks. -- -Andrew Thaddeus Martin

All of the other utilities functions from these packages would not be moved to `base`; they would remain in `free`
Importing the types without the functions seems like people would still end up depending on `free` to get those (or copy/paste the definitions). I can understand not wanting to pull the `MonadFree` typeclass and related functions into `base`, but there are a lot of functions in `free` which don't depend on that but are still useful. -- Michael Walker (http://www.barrucadu.co.uk)

I am not opposed to bringing over the helper functions as well. Those
are very useful, and I almost always need to tear down `Free` with
`iter` or `iterA`. I was trying to keep the scope of the changes down
to just the data types for several reasons.
- The data types are the only types that library maintainers actually
need in order to provide instances.
- Some of the helper functions (like _Pure and _Free) have a Choice
constraint and require a `profunctors` dependency. As you mention,
MonadFree is probably not a good candidate for `base` either. So, to
not break people's stuff, we would have to leave `Control.Monad.Free`
in `free` (which would basically reexport stuff and provide _Pure and
_Free), and we would have to add a module to `base`, something like
`Data.Fixed.Free`, which provides definitions for all the functions.
Usually, when modules are moved into `base`, it seems like people just
move the whole module, but that couldn't be done here.
- iterA vs iterM is a relic from the pre-AMP world. It may bother some
people to put things from a bygone age into `base`.
- Since there is no canonical library that provides `Fix`, we have to
figure out which utilities go in there (cata,ana,para,etc.)
Personally, I would be happy to see some of those utility functions in
base. But, it makes the path forward a little less clear, and it makes
it more likely that this proposal will stall. I would love to hear
more thoughts on how to make that happen as long as they have some
detail to them, detail that address at least the issues that I brought
up. I'll end by reiterating that in my mind, the most important thing
is getting the data types into base. Anything else is icing on the
cake.
On 10/16/16, Michael Walker
All of the other utilities functions from these packages would not be moved to `base`; they would remain in `free`
Importing the types without the functions seems like people would still end up depending on `free` to get those (or copy/paste the definitions). I can understand not wanting to pull the `MonadFree` typeclass and related functions into `base`, but there are a lot of functions in `free` which don't depend on that but are still useful.
-- Michael Walker (http://www.barrucadu.co.uk)
-- -Andrew Thaddeus Martin

On 16/10/16 11:21, Andrew Martin wrote:
The advantage this offers is that Free and Cofree would be able to enjoy a greater number of typeclass instances provided libraries across the ecosystem. As it stands, adding the somewhat heavy `free` dependency is not a good choice for libraries like `aeson`, `mustache`, and `hashable`. In the case of Fix, the ecosystem currently lacks a canonical library that provides it (recursion-schemes and data-fix both offer the same definition though, and various tutorials all define it the same way). It could benefit from the new instances as well.
This is a problem I see a lot, having to pull a "heavy" dependency to implement an instance and avoid orphans. I don't favor making a monolith in `base` for this, it goes against modularity and is a maintainer risk for base. Can cabal flags + CPP be abused to implement the instances on demand if the constrains are meet?. That would solve this problem at the cost of having to remember package-flags. -- Ruben Astudillo

Thanks for weighing in. It is possible to use cabal flags + CPP to work
around this, although I don't like doing that for the reasons you would
expect. I'm also not typically comfortable opening up an issue to ask a
package maintainer to add a flag to enable conditional dependencies for
instances. I believe that there is precedent for pulling data types that
offer a good abstraction into base (ie, moving Data.Functor.* from
transformers to base, moving Bifunctor into base), but I don't know exactly
what threshold needs to be cleared to make a compelling argument for doing
this.
-Andrew Martin
On Sun, Oct 16, 2016 at 2:49 PM, Ruben Astudillo
On 16/10/16 11:21, Andrew Martin wrote:
The advantage this offers is that Free and Cofree would be able to enjoy a greater number of typeclass instances provided libraries across the ecosystem. As it stands, adding the somewhat heavy `free` dependency is not a good choice for libraries like `aeson`, `mustache`, and `hashable`. In the case of Fix, the ecosystem currently lacks a canonical library that provides it (recursion-schemes and data-fix both offer the same definition though, and various tutorials all define it the same way). It could benefit from the new instances as well.
This is a problem I see a lot, having to pull a "heavy" dependency to implement an instance and avoid orphans. I don't favor making a monolith in `base` for this, it goes against modularity and is a maintainer risk for base. Can cabal flags + CPP be abused to implement the instances on demand if the constrains are meet?. That would solve this problem at the cost of having to remember package-flags.
-- Ruben Astudillo
-- -Andrew Thaddeus Martin

On Sun, 16 Oct 2016, Andrew Martin wrote:
Thanks for weighing in. It is possible to use cabal flags + CPP to work around this, although I don't like doing that for the reasons you would expect. I'm also not typically comfortable opening up an issue to ask a package maintainer to add a flag to enable conditional dependencies for instances.
Conditionally compiling instances into a package is not an option. If another package imports a certain version of your package it can expect the availability of all instances. There is no other way for a package to assert certain instances other than specifying the package version.

Like I said, I don't like doing things like this for the reasons that you would expect. I don't like that it breaks the PVP, makes running your test suite more difficult, and makes your haddocks not include information that might be available. But to get back to the original proposal, what are your thoughts on providing Free, Cofree, and Fix in base? I gather from your previous comment that you would prefer anything to conditional instances, but do you find that these recursive data types are commonly used enough to merit inclusion in base? On Sun, Oct 16, 2016 at 3:34 PM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sun, 16 Oct 2016, Andrew Martin wrote:
Thanks for weighing in. It is possible to use cabal flags + CPP to work
around this, although I don't like doing that for the reasons you would expect. I'm also not typically comfortable opening up an issue to ask a package maintainer to add a flag to enable conditional dependencies for instances.
Conditionally compiling instances into a package is not an option. If another package imports a certain version of your package it can expect the availability of all instances. There is no other way for a package to assert certain instances other than specifying the package version.
-- -Andrew Thaddeus Martin

On Sun, 16 Oct 2016, Andrew Martin wrote:
Like I said, I don't like doing things like this for the reasons that you would expect. I don't like that it breaks the PVP, makes running your test suite more difficult, and makes your haddocks not include information that might be available. But to get back to the original proposal, what are your thoughts on providing Free, Cofree, and Fix in base? I gather from your previous comment that you would prefer anything to conditional instances, but do you find that these recursive data types are commonly used enough to merit inclusion in base?
I haven't used them so far.

"AM" == Andrew Martin
writes:
AM> I would gladly help with any of the work that needs to be done to make AM> this happen. I believe that Fix and Free (and Cofree to a lesser extent) AM> have proved themselves over years of use in the ecosystem. I would AM> appreciate any feedback or thoughts that others have on this topic. What advantage is there to having them in base, rather than living in the 'free' package as they do now? -- John Wiegley GPG fingerprint = 4710 CF98 AF9B 327B B80F http://newartisans.com 60E1 46C4 BD1A 7AC1 4BA2

The advantages I outlined were:
The advantage this offers is that Free and Cofree would be able to
enjoy a greater number of typeclass instances provided libraries
across the ecosystem. As it stands, adding the somewhat heavy `free`
dependency is not a good choice for libraries like `aeson`,
`mustache`, and `hashable`. In the case of Fix, the ecosystem
currently lacks a canonical library that provides it
(recursion-schemes and data-fix both offer the same definition though,
and various tutorials all define it the same way). It could benefit
from the new instances as well.
On Mon, Oct 17, 2016 at 2:31 PM, John Wiegley
"AM" == Andrew Martin
writes: AM> I would gladly help with any of the work that needs to be done to make AM> this happen. I believe that Fix and Free (and Cofree to a lesser extent) AM> have proved themselves over years of use in the ecosystem. I would AM> appreciate any feedback or thoughts that others have on this topic.
What advantage is there to having them in base, rather than living in the 'free' package as they do now?
-- John Wiegley GPG fingerprint = 4710 CF98 AF9B 327B B80F http://newartisans.com 60E1 46C4 BD1A 7AC1 4BA2
-- -Andrew Thaddeus Martin

I am against extending `base`, as the functionality is already available
outside it---a smaller `base` is easier to maintain, and gives us more room
to evolve and change things. If the `free` package is considered "too
heavy" of a dependency, then perhaps that package should be split into
multiple smaller packages that provide the required functionality.
-Iavor
On Tue, Oct 18, 2016 at 8:34 AM, Andrew Martin
The advantages I outlined were:
The advantage this offers is that Free and Cofree would be able to enjoy a greater number of typeclass instances provided libraries across the ecosystem. As it stands, adding the somewhat heavy `free` dependency is not a good choice for libraries like `aeson`, `mustache`, and `hashable`. In the case of Fix, the ecosystem currently lacks a canonical library that provides it (recursion-schemes and data-fix both offer the same definition though, and various tutorials all define it the same way). It could benefit from the new instances as well.
On Mon, Oct 17, 2016 at 2:31 PM, John Wiegley
wrote: > "AM" == Andrew Martin
writes: AM> I would gladly help with any of the work that needs to be done to make AM> this happen. I believe that Fix and Free (and Cofree to a lesser extent) AM> have proved themselves over years of use in the ecosystem. I would AM> appreciate any feedback or thoughts that others have on this topic.
What advantage is there to having them in base, rather than living in the 'free' package as they do now?
-- John Wiegley GPG fingerprint = 4710 CF98 AF9B 327B B80F http://newartisans.com 60E1 46C4 BD1A 7AC1 4BA2
-- -Andrew Thaddeus Martin
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

As a user of both mustache and aeson, I would be very happy for them to add
a dependency on free. It seems like the ideal solution to me.
On Thu, Oct 20, 2016 at 12:02 PM, Iavor Diatchki
I am against extending `base`, as the functionality is already available outside it---a smaller `base` is easier to maintain, and gives us more room to evolve and change things. If the `free` package is considered "too heavy" of a dependency, then perhaps that package should be split into multiple smaller packages that provide the required functionality.
-Iavor
On Tue, Oct 18, 2016 at 8:34 AM, Andrew Martin
wrote: The advantages I outlined were:
The advantage this offers is that Free and Cofree would be able to enjoy a greater number of typeclass instances provided libraries across the ecosystem. As it stands, adding the somewhat heavy `free` dependency is not a good choice for libraries like `aeson`, `mustache`, and `hashable`. In the case of Fix, the ecosystem currently lacks a canonical library that provides it (recursion-schemes and data-fix both offer the same definition though, and various tutorials all define it the same way). It could benefit from the new instances as well.
On Mon, Oct 17, 2016 at 2:31 PM, John Wiegley
wrote: >> "AM" == Andrew Martin
writes: AM> I would gladly help with any of the work that needs to be done to make AM> this happen. I believe that Fix and Free (and Cofree to a lesser extent) AM> have proved themselves over years of use in the ecosystem. I would AM> appreciate any feedback or thoughts that others have on this topic.
What advantage is there to having them in base, rather than living in the 'free' package as they do now?
-- John Wiegley GPG fingerprint = 4710 CF98 AF9B 327B B80F http://newartisans.com 60E1 46C4 BD1A 7AC1 4BA2
-- -Andrew Thaddeus Martin
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Is there some kind of general rule for when base should absorb things. In the last several years, it's pulled in Data.Functor.Identity, Data.Functor.Compose, Eq1, Ord1, Bifunctor. Is there any kind set of criteria these had to meet to be pulled in? Sent from my iPhone
On Oct 20, 2016, at 12:02 PM, Iavor Diatchki
wrote: I am against extending `base`, as the functionality is already available outside it---a smaller `base` is easier to maintain, and gives us more room to evolve and change things. If the `free` package is considered "too heavy" of a dependency, then perhaps that package should be split into multiple smaller packages that provide the required functionality.
-Iavor
On Tue, Oct 18, 2016 at 8:34 AM, Andrew Martin
wrote: The advantages I outlined were: The advantage this offers is that Free and Cofree would be able to enjoy a greater number of typeclass instances provided libraries across the ecosystem. As it stands, adding the somewhat heavy `free` dependency is not a good choice for libraries like `aeson`, `mustache`, and `hashable`. In the case of Fix, the ecosystem currently lacks a canonical library that provides it (recursion-schemes and data-fix both offer the same definition though, and various tutorials all define it the same way). It could benefit from the new instances as well. On Mon, Oct 17, 2016 at 2:31 PM, John Wiegley
wrote: >> "AM" == Andrew Martin
writes: AM> I would gladly help with any of the work that needs to be done to make AM> this happen. I believe that Fix and Free (and Cofree to a lesser extent) AM> have proved themselves over years of use in the ecosystem. I would AM> appreciate any feedback or thoughts that others have on this topic.
What advantage is there to having them in base, rather than living in the 'free' package as they do now?
-- John Wiegley GPG fingerprint = 4710 CF98 AF9B 327B B80F http://newartisans.com 60E1 46C4 BD1A 7AC1 4BA2
-- -Andrew Thaddeus Martin
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

"AM" == Andrew Martin
writes:
AM> Is there some kind of general rule for when base should absorb things. In AM> the last several years, it's pulled in Data.Functor.Identity, AM> Data.Functor.Compose, Eq1, Ord1, Bifunctor. Is there any kind set of AM> criteria these had to meet to be pulled in? A principle I've inferred is that it goes into base if (a) it's foundational, and (b) there's really just one way to express the principle, rather than multiple ways with inherent trade-offs between them. For example, Free is known to have significant costs, which are ameliorated (though made worse in the other direction) by its tagless encoding. Since the two representations are isomorphic, it becomes strange for base to canonize one over the other; but with Data.Functor.Identity, there is no such contention. -- John Wiegley GPG fingerprint = 4710 CF98 AF9B 327B B80F http://newartisans.com 60E1 46C4 BD1A 7AC1 4BA2

On 2016-10-20 19:41, John Wiegley wrote:
"AM" == Andrew Martin
writes: AM> Is there some kind of general rule for when base should absorb things. In AM> the last several years, it's pulled in Data.Functor.Identity, AM> Data.Functor.Compose, Eq1, Ord1, Bifunctor. Is there any kind set of AM> criteria these had to meet to be pulled in?
A principle I've inferred is that it goes into base if (a) it's foundational, and (b) there's really just one way to express the principle, rather than multiple ways with inherent trade-offs between them.
For example, Free is known to have significant costs, which are ameliorated (though made worse in the other direction) by its tagless encoding. Since the two representations are isomorphic, it becomes strange for base to canonize one over the other; but with Data.Functor.Identity, there is no such contention.
Wasn't this thread about only pulling in Fix (from the 'free' package), or am I missing something?

"BA" == Bardur Arantsson
writes:
BA> Wasn't this thread about only pulling in Fix (from the 'free' package), or BA> am I missing something? Right; just Fix is OK with me. I would like for that to be in base. -- John Wiegley GPG fingerprint = 4710 CF98 AF9B 327B B80F http://newartisans.com 60E1 46C4 BD1A 7AC1 4BA2
participants (8)
-
Andrew Martin
-
Bardur Arantsson
-
davean
-
Henning Thielemann
-
Iavor Diatchki
-
John Wiegley
-
Michael Walker
-
Ruben Astudillo