duoids 0.0.1.0 → 0.1.0.0
raw patch · 6 files changed
+464/−43 lines, 6 filesdep ~doctestdep ~no-recursionsetup-changedPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: doctest, no-recursion
API changes (from Hackage documentation)
- Control.Duoidal: instance GHC.Base.Applicative f => GHC.Base.Applicative (Control.Duoidal.Parallel (Control.Duoidal.Commutative f))
- Control.Duoidal: instance GHC.Base.Applicative f => GHC.Base.Applicative (Control.Duoidal.Sequential (Control.Duoidal.Commutative f))
+ Control.Duoidal: commutativeAp :: forall (f :: Type -> Type) a b. Monad f => Parallel f (a -> b) -> Parallel f a -> Parallel f b
+ Control.Duoidal: instance (Data.Duoid.Duoid a, Data.Duoid.Duoid b) => GHC.Base.Applicative (Control.Duoidal.Parallel ((,,) a b))
+ Control.Duoidal: instance (Data.Duoid.Duoid a, Data.Duoid.Duoid b) => GHC.Base.Applicative (Control.Duoidal.Sequential ((,,) a b))
+ Control.Duoidal: instance (Data.Duoid.Duoid a, Data.Duoid.Duoid b) => GHC.Base.Monad (Control.Duoidal.Sequential ((,,) a b))
+ Control.Duoidal: instance (Data.Duoid.Duoid a, Data.Duoid.Duoid b, Data.Duoid.Duoid c) => GHC.Base.Applicative (Control.Duoidal.Parallel ((,,,) a b c))
+ Control.Duoidal: instance (Data.Duoid.Duoid a, Data.Duoid.Duoid b, Data.Duoid.Duoid c) => GHC.Base.Applicative (Control.Duoidal.Sequential ((,,,) a b c))
+ Control.Duoidal: instance (Data.Duoid.Duoid a, Data.Duoid.Duoid b, Data.Duoid.Duoid c) => GHC.Base.Monad (Control.Duoidal.Sequential ((,,,) a b c))
+ Control.Duoidal: instance (Data.Duoid.Normal a, Data.Duoid.Normal b) => Control.Duoidal.Normal ((,,) a b)
+ Control.Duoidal: instance (Data.Duoid.Normal a, Data.Duoid.Normal b, Data.Duoid.Normal c) => Control.Duoidal.Normal ((,,,) a b c)
+ Control.Duoidal: instance Control.Duoidal.Normal ((->) r)
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Complex.Complex
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Functor.Identity.Identity
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Monoid.First
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Monoid.Last
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Ord.Down
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Proxy.Proxy
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Semigroup.First
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Semigroup.Internal.Dual
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Semigroup.Internal.Product
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Semigroup.Internal.Sum
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Semigroup.Last
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Semigroup.Max
+ Control.Duoidal: instance Control.Duoidal.Normal Data.Semigroup.Min
+ Control.Duoidal: instance Control.Duoidal.Normal GHC.Maybe.Maybe
+ Control.Duoidal: instance Control.Duoidal.Normal GHC.Tuple.Prim.Solo
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel ((->) r))
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Complex.Complex)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Functor.Identity.Identity)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Monoid.First)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Monoid.Last)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Ord.Down)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Proxy.Proxy)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Semigroup.First)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Semigroup.Internal.Dual)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Semigroup.Internal.Product)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Semigroup.Internal.Sum)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Semigroup.Last)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Semigroup.Max)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel Data.Semigroup.Min)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel GHC.Maybe.Maybe)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Parallel GHC.Tuple.Prim.Solo)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential ((->) r))
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Complex.Complex)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Functor.Identity.Identity)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Monoid.First)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Monoid.Last)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Ord.Down)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Proxy.Proxy)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Semigroup.First)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Semigroup.Internal.Dual)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Semigroup.Internal.Product)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Semigroup.Internal.Sum)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Semigroup.Last)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Semigroup.Max)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential Data.Semigroup.Min)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential GHC.Maybe.Maybe)
+ Control.Duoidal: instance GHC.Base.Applicative (Control.Duoidal.Sequential GHC.Tuple.Prim.Solo)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential ((->) r))
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Complex.Complex)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Functor.Identity.Identity)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Monoid.First)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Monoid.Last)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Ord.Down)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Proxy.Proxy)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Semigroup.First)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Semigroup.Internal.Dual)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Semigroup.Internal.Product)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Semigroup.Internal.Sum)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Semigroup.Last)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Semigroup.Max)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential Data.Semigroup.Min)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential GHC.Maybe.Maybe)
+ Control.Duoidal: instance GHC.Base.Monad (Control.Duoidal.Sequential GHC.Tuple.Prim.Solo)
+ Control.Duoidal: instance GHC.Base.Monad f => Control.Duoidal.Normal (Control.Duoidal.Commutative f)
+ Control.Duoidal: instance GHC.Base.Monad f => GHC.Base.Applicative (Control.Duoidal.Commutative f)
+ Control.Duoidal: instance GHC.Base.Monad f => GHC.Base.Applicative (Control.Duoidal.Parallel (Control.Duoidal.Commutative f))
+ Control.Duoidal: instance GHC.Base.Monad f => GHC.Base.Applicative (Control.Duoidal.Sequential (Control.Duoidal.Commutative f))
+ Control.Duoidal: instance GHC.Base.Monad f => GHC.Base.Monad (Control.Duoidal.Commutative f)
+ Control.Duoidal: instance GHC.Base.Monoid a => GHC.Base.Applicative (Control.Duoidal.Parallel (Data.Functor.Const.Const a))
+ Control.Duoidal: instance GHC.Base.Monoid a => GHC.Base.Applicative (Control.Duoidal.Sequential (Data.Functor.Const.Const a))
+ Control.Duoidal: instance GHC.Base.Monoid a => GHC.Base.Monad (Control.Duoidal.Sequential (Data.Functor.Const.Const a))
+ Control.Duoidal: sequentialAp :: forall (f :: Type -> Type) a b. Monad f => Sequential f (a -> b) -> Sequential f a -> Sequential f b
Files
- CHANGELOG.md +38/−2
- README.md +5/−1
- Setup.hs +0/−1
- docs/license-report.md +4/−3
- duoids.cabal +31/−18
- src/Control/Duoidal.hs +386/−18
CHANGELOG.md view
@@ -5,10 +5,46 @@ The format is based on [Keep a Changelog 1.1](https://keepachangelog.com/en/1.1.0/), and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). -## [0.0.1.0] -+## [0.1.0.0] - 2026-08-04 ### Added +- `Applicative` and `Monad` instances for `Commutative` itself, so it can be+ used with `DerivingVia` to give your own commutative `Monad` a `Duoidal`+ instance, rather than only being usable through `Parallel` and `Sequential`+- `commutativeAp` and `sequentialAp`+- `Normal` duoidal instances for the commutative functors in base: `Complex`,+ `Down`, `Dual`, `Identity`, `Max`, `Maybe`, `Min`, `Monoid.First`,+ `Monoid.Last`, `Monoid.Product`, `Proxy`, `Semigroup.First`, `Semigroup.Last`,+ `Solo`, `Sum`, `->`, `(,,)`, `(,,,)`, and `Const`+- Cabal flag `lint`, which (when disabled, as is the default) allows the+ dependency graph to be pruned, potentially avoiding solver & compilation+ issues.++### Changed++- `Applicative (Parallel (Commutative f))` and `Applicative (Sequential+ (Commutative f))` now require `f` to be a `Monad` rather than merely an+ `Applicative`. `Commutative` was always documented as being for commutative+ `Monad`s, but the instances asked for less than they meant; the new+ `Commutative` instances need the stronger constraint.++### Deprecated++- `sequentialLiftA2` — use `sequentialAp` instead++### Fixed++- `no-recursion` is no longer a dependency by default (thanks to the+ aforementioned `lint` change).++## [0.0.1.0] - 2025-11-17++### Added+ - initial release of this package -[0.0.1.0]: https://github.com/sellout/duoids/releases/tag/v0.0.1.0+<!-- NB: The version on the left is the Haskell package version (PVP), the version on the right is the repo (tag) version (SemVer). Their only relationship is that a change of any severity on the left implies a change of at least that severity on the right. -->++[0.1.0.0]: https://github.com/sellout/duoids/compare/v0.1.0...v1.0.0+[0.0.1.0]: https://github.com/sellout/duoids/releases/tag/v0.1.0
README.md view
@@ -107,11 +107,15 @@ ### [either](https://hackage.haskell.org/package/either) -The `either` package has a `Validation` type that’s isomorphic to `Either` and has an applicative instance that’s the same as the `Parallel (Either e)` instance here. However, it doesn’t have anything like the `Duoidal` class, and so requires manual conversion back and forth between `Either` and `Validation`.+The `either` package has a `Validation` type that’s isomorphic to `Either` and has an `Applicative` instance that’s the same as the `Parallel (Either e)` instance here. However, it doesn’t have anything like the `Duoidal` class, and so requires manual conversion back and forth between `Either` and `Validation`. ### [Haskerwaul](https://github.com/sellout/haskerwaul#readme) A broader package that contains a more general (category polymorphic) implementation of duoids. It’s also much less pragmatic.++### [multi-except](https://hackage.haskell.org/package/multi-except)++This seems like another approach to `Validation`, but I haven’t used it. ### [United Monoids](https://github.com/snowleopard/united)
Setup.hs view
@@ -7,7 +7,6 @@ -- Warns even when `Unsafe` is explicit, not inferred. See -- https://gitlab.haskell.org/ghc/ghc/-/issues/16689 {-# OPTIONS_GHC -Wno-unsafe #-}-{-# OPTIONS_GHC -fplugin=NoRecursion #-} module Main (main) where
docs/license-report.md view
@@ -9,7 +9,7 @@ | Name | Version | [SPDX](https://spdx.org/licenses/) License Id | Description | Also depended upon by | | --- | --- | --- | --- | --- | | **`base`** | [`4.20.0.0`](http://hackage.haskell.org/package/base-4.20.0.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/base-4.20.0.0/src/LICENSE) | Core data structures and operations | *(core library)* |-| `no-recursion` | [`0.3.0.0`](http://hackage.haskell.org/package/no-recursion-0.3.0.0) | [`(AGPL-3.0-only WITH Universal-FOSS-exception-1.0 OR AGPL-3.0-only OR LicenseRef-commercial)`](http://hackage.haskell.org/package/no-recursion-0.3.0.0/src/LICENSE) | A GHC plugin to remove support for recursion | |+| `no-recursion` | [`0.4.0.1`](http://hackage.haskell.org/package/no-recursion-0.4.0.1) | [`(AGPL-3.0-only WITH Universal-FOSS-exception-1.0 OR LicenseRef-proprietary)`](http://hackage.haskell.org/package/no-recursion-0.4.0.1/src/LICENSE) | A GHC plugin to remove support for recursion | | ## Indirect transitive dependencies @@ -23,10 +23,11 @@ | **`directory`** | [`1.3.8.3`](http://hackage.haskell.org/package/directory-1.3.8.3) | [`BSD-3-Clause`](http://hackage.haskell.org/package/directory-1.3.8.3/src/LICENSE) | Platform-agnostic library for filesystem operations | `ghc`, `ghc-boot`, `hpc`, `process` | | **`exceptions`** | [`0.10.7`](http://hackage.haskell.org/package/exceptions-0.10.7) | [`BSD-3-Clause`](http://hackage.haskell.org/package/exceptions-0.10.7/src/LICENSE) | Extensible optionally-pure exceptions | `filepath`, `ghc`, `os-string`, `semaphore-compat` | | **`filepath`** | [`1.5.2.0`](http://hackage.haskell.org/package/filepath-1.5.2.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/filepath-1.5.2.0/src/LICENSE) | Library for manipulating FilePaths in a cross platform way. | `directory`, `ghc`, `ghc-boot`, `ghci`, `hpc`, `process`, `unix` |-| **`ghc`** | [`9.10.1`](http://hackage.haskell.org/package/ghc-9.10.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-9.10.1/src/LICENSE) | The GHC API | `no-recursion` |+| **`ghc`** | [`9.10.1`](http://hackage.haskell.org/package/ghc-9.10.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-9.10.1/src/LICENSE) | The GHC API | `ghc-compat-plugin`, `no-recursion` | | **`ghc-bignum`** | [`1.3`](http://hackage.haskell.org/package/ghc-bignum-1.3) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-bignum-1.3/src/LICENSE) | GHC BigNum library | `ghc-internal` | | **`ghc-boot`** | [`9.10.1`](http://hackage.haskell.org/package/ghc-boot-9.10.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-boot-9.10.1/src/LICENSE) | Shared functionality between GHC and its boot libraries | `ghc`, `ghci` |-| **`ghc-boot-th`** | [`9.10.1`](http://hackage.haskell.org/package/ghc-boot-th-9.10.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-boot-th-9.10.1/src/LICENSE) | Shared functionality between GHC and the @template-haskell@ library | `ghc-boot`, `template-haskell` |+| **`ghc-boot-th`** | [`9.10.1`](http://hackage.haskell.org/package/ghc-boot-th-9.10.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-boot-th-9.10.1/src/LICENSE) | Shared functionality between GHC and the @template-haskell@ library | `ghc-boot`, `ghc-compat-plugin`, `template-haskell` |+| `ghc-compat-plugin` | [`0.1.0.1`](http://hackage.haskell.org/package/ghc-compat-plugin-0.1.0.1) | [`AGPL-3.0-only`](http://hackage.haskell.org/package/ghc-compat-plugin-0.1.0.1/src/LICENSE.AGPL-3.0-only) | Eases support for multiple GHC versions | `no-recursion` | | **`ghc-heap`** | [`9.10.1`](http://hackage.haskell.org/package/ghc-heap-9.10.1) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-heap-9.10.1/src/LICENSE) | Functions for walking GHC's heap | `ghc`, `ghci` | | **`ghc-internal`** | [`9.1001.0`](http://hackage.haskell.org/package/ghc-internal-9.1001.0) | [`BSD-3-Clause`](http://hackage.haskell.org/package/ghc-internal-9.1001.0/src/LICENSE) | Basic libraries | `base`, `ghc-heap` | | **`ghc-platform`** | [`0.1.0.0`](http://hackage.haskell.org/package/ghc-platform-0.1.0.0) | *MISSING* | *MISSING* | `ghc-boot` |
duoids.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0 name: duoids-version: 0.0.1.0+version: 0.1.0.0 synopsis: Unifying parallel and sequential operations description: Duoids relate a pair of monoids, where one can be seen as “parallel” and the other “sequential”.@@ -38,17 +38,6 @@ location: https://github.com/sellout/duoids.git subdir: core -flag noisy-deprecations- description:- Prior to GHC 9.10, the @DEPRECATED@ pragma can’t distinguish between terms- and types. Consenquently, you can get spurious warnings when there’s a name- collision and the name in the other namespace is deprecated. Or you can- choose to not get those warnings, at the risk of not being warned when- there’s a name collision and the namespace you’re referencing is the one- that’s deprecated.- default: True- manual: False- custom-setup setup-depends: -- TODO: Due to haskell/cabal#3751, `Cabal` has to be specified even though@@ -59,8 +48,27 @@ Cabal >= 3.0 && < 99, base ^>= {4.18.0, 4.19.0, 4.20.0, 4.21.0}, cabal-doctest ^>= {1.0.0},- no-recursion ^>= {0.2.0, 0.3.0}, +flag noisy-deprecations+ description:+ Prior to GHC 9.10, the @DEPRECATED@ pragma can’t distinguish between terms+ and types. Consenquently, you can get spurious warnings when there’s a name+ collision and the name in the other namespace is deprecated. Or you can+ choose to not get those warnings, at the risk of not being warned when+ there’s a name collision and the namespace you’re referencing is the one+ that’s deprecated.+ default: True+ -- Because disabling this flag won’t help the solver.+ manual: True++flag lint+ description:+ Compile with "NoRecursion" enabled. This is intended for developers of this+ package.+ default: False+ -- Because disabling this flag won’t help the solver.+ manual: True+ -- This mimics the GHC2024 extension -- (https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/control.html?highlight=doandifthenelse#extension-GHC2024), -- but supporting compilers back to GHC 8.0. If the oldest supported compiler@@ -84,7 +92,6 @@ import: GHC2024 build-depends: base ^>= {4.18.0, 4.19.0, 4.20.0, 4.21.0},- no-recursion ^>= {0.2.0, 0.3.0}, ghc-options: -Weverything -- This one just reports unfixable things, AFAICT.@@ -94,7 +101,6 @@ -- Warns even when `Unsafe` is explicit, not inferred. See -- https://gitlab.haskell.org/ghc/ghc/-/issues/16689 -Wno-unsafe- -fplugin=NoRecursion if impl(ghc >= 9.8.1) ghc-options: -- Inference good.@@ -121,11 +127,18 @@ NoStarIsType NoTypeApplications if flag(noisy-deprecations)- cpp-options: -DSELLOUT_NOISY_DEPRECATIONS+ cpp-options:+ -DSELLOUT_NOISY_DEPRECATIONS+ if flag(lint)+ build-depends:+ no-recursion ^>= {0.2.0, 0.3.0, 0.4.0},+ ghc-options:+ -fplugin=NoRecursion library import: defaults- hs-source-dirs: src+ hs-source-dirs:+ src exposed-modules: Control.Duoidal Control.Duoidal.Either@@ -141,7 +154,7 @@ hs-source-dirs: tests main-is: doctests.hs build-depends:- doctest ^>= {0.21.1, 0.22.6, 0.24.0},+ doctest ^>= {0.21.1, 0.22.6, 0.24.0, 0.25.0}, duoids, -- TODO: The sections below here are necessary because we don’t have control -- over the generated `Build_doctests.hs` file. So we have to silence
src/Control/Duoidal.hs view
@@ -141,16 +141,24 @@ -- * instance helpers normalPure,+ sequentialAp, sequentialBind, sequentialLiftA2, sequentialPure, -- * duoids from commutative `Monad`s Commutative (Commutative, getCommutative),+ commutativeAp, ) where -import "base" Control.Applicative (Alternative, Applicative, empty, (<|>))+import "base" Control.Applicative+ ( Alternative,+ Applicative,+ Const (Const),+ empty,+ (<|>),+ ) import "base" Control.Applicative qualified as Base ( liftA2, liftA3,@@ -163,7 +171,8 @@ import "base" Control.Category ((.)) import "base" Control.Monad (Monad) import "base" Control.Monad qualified as Base- ( forever,+ ( ap,+ forever, join, liftM2, return,@@ -182,18 +191,25 @@ bitraverse, ) import "base" Data.Bool (Bool)+import "base" Data.Complex (Complex) import "base" Data.Either (Either (Left, Right), either) import "base" Data.Eq (Eq) import "base" Data.Foldable (Foldable) import "base" Data.Foldable qualified as Base (for_, traverse_) import "base" Data.Function (const, ($)) import "base" Data.Functor (Functor, fmap)+import "base" Data.Functor.Identity (Identity) import "base" Data.Kind (Constraint, Type)-import "base" Data.Monoid (Monoid, mempty)-import "base" Data.Ord (Ord)-import "base" Data.Semigroup (Semigroup, (<>))+import "base" Data.Maybe (Maybe)+import "base" Data.Monoid (Dual, Monoid, Sum, mempty)+import "base" Data.Monoid qualified as Monoid+import "base" Data.Ord (Down, Ord)+import "base" Data.Proxy (Proxy)+import "base" Data.Semigroup (Max, Min, Semigroup, (<>))+import "base" Data.Semigroup qualified as Semigroup import "base" Data.Traversable (Traversable) import "base" Data.Traversable qualified as Base (for, traverse)+import "base" Data.Tuple (Solo) import "base" GHC.TypeError (ErrorMessage (Text), TypeError) import "base" System.IO (IO) import "base" Text.Read (Read)@@ -467,7 +483,12 @@ Sequential f b -> Sequential f c sequentialLiftA2 f (Sequential a) = Sequential . Base.liftA2 f a . getSequential+{-# DEPRECATED sequentialLiftA2 "use ‘sequentialAp’ instead" #-} +sequentialAp ::+ (Monad f) => Sequential f (a -> b) -> Sequential f a -> Sequential f b+sequentialAp (Sequential f) = Sequential . Base.ap f . getSequential+ sequentialBind :: (Monad f) => Sequential f a -> (a -> Sequential f b) -> Sequential f b sequentialBind (Sequential a) f = Sequential $ a Base.>>= (getSequential . f)@@ -476,25 +497,329 @@ -- | Commutative `Monad`s form a duoid with themselves. ----- __NB__: Don’t use this newtype on a non-commutative Monad.+-- You can use this with @DerivingVia@ to create instances for your own+-- commutative `Monad`s.+--+-- For existing types, instances for types in base should be available here,+-- but those for other packages may not exist. For those that don’t, you can+--+-- 1. wrap the type in `Commutative` when you need the instance,+-- 2. define orphan instances that look like the instances for `Commutative`, or+-- 3. use the provided operations (like `commutativeAp`) directly.+--+-- Some examples of commutative monads:+-- - those isomorphic to `Identity` (many newtypes fall into this bucket)+-- - reader (@->@)+-- - `Maybe`+-- - `Proxy`+--+-- You can also wrap types that already have `Duoidal` instances in+-- `Commutative` as well (as long as they have an unwrapped `Monad` instance).+-- If their existing `Duoidal` instance isn’t the commutative one, the+-- `Commutative` wrapper will give you the commutative one. I don’t know if+-- this one is correct, but if you have a commutative writer (say, @`Writer`+-- (`Set` `Char`)@), wrapping it in `Commutative` would give you a `Duoidal`+-- instance that behaves commutatively. However, @`Set` a@ should already have+-- a commutative `Duoid` instance, so I don’t think it actually buys you+-- anything.+--+-- __NB__: Don’t use this newtype to turn a non-commutative `Monad` into a+-- duoid. type Commutative :: forall {k}. (k -> Type) -> k -> Type newtype Commutative f a = Commutative {getCommutative :: f a} deriving stock (Eq, Ord, Read, Show, Functor, Foldable, Traversable) -instance (Applicative f) => Applicative (Parallel (Commutative f)) where- pure = Parallel . Commutative . Base.pure- liftA2 f (Parallel (Commutative a)) (Parallel (Commutative b)) =- Parallel . Commutative $ Base.liftA2 f a b+instance (Monad f) => Applicative (Commutative f) where+ pure = Commutative . Base.return+ Commutative f <*> Commutative a = Commutative $ Base.ap f a -instance (Applicative f) => Applicative (Sequential (Commutative f)) where- pure = Sequential . Commutative . Base.pure- liftA2 f (Sequential (Commutative a)) (Sequential (Commutative b)) =- Sequential . Commutative $ Base.liftA2 f a b+instance (Monad f) => Monad (Commutative f) where+ Commutative a >>= f = Commutative $ a Base.>>= (getCommutative . f) +commutativeAp ::+ (Monad f) =>+ Parallel f (a -> b) ->+ Parallel f a ->+ Parallel f b+commutativeAp (Parallel f) = Parallel . Base.ap f . getParallel++instance (Monad f) => Applicative (Parallel (Commutative f)) where+ pure = normalPure+ (<*>) = commutativeAp++instance (Monad f) => Applicative (Sequential (Commutative f)) where+ pure = sequentialPure+ (<*>) = sequentialAp+ instance (Monad f) => Monad (Sequential (Commutative f)) where- Sequential (Commutative a) >>= f =- Sequential . Commutative $ a Base.>>= (getCommutative . getSequential . f)+ (>>=) = sequentialBind +instance (Monad f) => Normal (Commutative f)++-- `Complex` is a commutative duoidal functor++instance Applicative (Parallel Complex) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Complex) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Complex) where+ (>>=) = sequentialBind++instance Normal Complex++-- `Down` is a commutative duoidal functor++instance Applicative (Parallel Down) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Down) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Down) where+ (>>=) = sequentialBind++instance Normal Down++-- `Dual` is a commutative duoidal functor++instance Applicative (Parallel Dual) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Dual) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Dual) where+ (>>=) = sequentialBind++instance Normal Dual++-- `Monoid.First` is a commutative duoidal functor++instance Applicative (Parallel Monoid.First) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Monoid.First) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Monoid.First) where+ (>>=) = sequentialBind++instance Normal Monoid.First++-- `Semigroup.First` is a commutative duoidal functor++instance Applicative (Parallel Semigroup.First) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Semigroup.First) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Semigroup.First) where+ (>>=) = sequentialBind++instance Normal Semigroup.First++-- `Identity` is a commutative duoidal functor++instance Applicative (Parallel Identity) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Identity) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Identity) where+ (>>=) = sequentialBind++instance Normal Identity++-- `Monoid.Last` is a commutative duoidal functor++instance Applicative (Parallel Monoid.Last) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Monoid.Last) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Monoid.Last) where+ (>>=) = sequentialBind++instance Normal Monoid.Last++-- `Semigroup.Last` is a commutative duoidal functor++instance Applicative (Parallel Semigroup.Last) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Semigroup.Last) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Semigroup.Last) where+ (>>=) = sequentialBind++instance Normal Semigroup.Last++-- `Max` is a commutative duoidal functor++instance Applicative (Parallel Max) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Max) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Max) where+ (>>=) = sequentialBind++instance Normal Max++-- `Maybe` is a commutative duoidal functor++instance Applicative (Parallel Maybe) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Maybe) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Maybe) where+ (>>=) = sequentialBind++instance Normal Maybe++-- `Min` is a commutative duoidal functor++instance Applicative (Parallel Min) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Min) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Min) where+ (>>=) = sequentialBind++instance Normal Min++-- `Monoid.Product` is a commutative duoidal functor++instance Applicative (Parallel Monoid.Product) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Monoid.Product) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Monoid.Product) where+ (>>=) = sequentialBind++instance Normal Monoid.Product++-- `Proxy` is a commutative duoidal functor++instance Applicative (Parallel Proxy) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Proxy) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Proxy) where+ (>>=) = sequentialBind++instance Normal Proxy++-- `Solo` is a commutative duoidal functor++instance Applicative (Parallel Solo) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Solo) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Solo) where+ (>>=) = sequentialBind++instance Normal Solo++-- `Sum` is a commutative duoidal functor++instance Applicative (Parallel Sum) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential Sum) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential Sum) where+ (>>=) = sequentialBind++instance Normal Sum++-- reader is a commutative duoidal functor++instance Applicative (Parallel ((->) r)) where+ pure = normalPure+ (<*>) = commutativeAp++instance Applicative (Sequential ((->) r)) where+ pure = sequentialPure+ (<*>) = sequentialAp++instance Monad (Sequential ((->) r)) where+ (>>=) = sequentialBind++instance Normal ((->) r)++-- Const++instance (Monoid a) => Applicative (Parallel (Const a)) where+ pure = normalPure+ liftA2 f (Parallel a) (Parallel b) = Parallel $ liftA2 f a b++instance (Monoid a) => Applicative (Sequential (Const a)) where+ pure = Sequential . pure+ liftA2 f (Sequential a) = Sequential . Base.liftA2 f a . getSequential++-- | The `Const` duoidal functor provides an illustration of why we need to have+-- both `Parallel` and `Sequential` newtypes – relying on the underlying+-- `Applicative` (and only having the `Sequential` newtype) would mean that+-- any duoidal structure would only have a `Monad` available under+-- `Sequential`, which would be a prettty serious impact. On the other hand,+-- relying on the underlying `Monad` (and only having the `Parallel` newtype)+-- is much more natural, but `Const`, for example, having a `Monad` instance+-- would make it basically useless, and the more interesting `Applicative`+-- instance would only be available under the `Parallel` netwype. The current+-- structure allows either the `Applicative` or `Monad` instance to be the one+-- exposed directly.+instance (Monoid a) => Monad (Sequential (Const a)) where+ Sequential (Const a) >>= _ = Sequential $ Const a+ -- Either instance (Semigroup e) => Applicative (Parallel (Either e)) where@@ -509,7 +834,7 @@ instance (Semigroup e) => Applicative (Sequential (Either e)) where pure = sequentialPure- liftA2 = sequentialLiftA2+ (<*>) = sequentialAp instance (Semigroup e) => Monad (Sequential (Either e)) where (>>=) = sequentialBind@@ -539,7 +864,7 @@ instance Applicative (Sequential IO) where pure = sequentialPure- liftA2 = sequentialLiftA2+ (<*>) = sequentialAp instance Monad (Sequential IO) where (>>=) = sequentialBind@@ -584,3 +909,46 @@ -- | A writer is a `Normal` `Duoidal` functor when the writee is a -- `Duoid.Normal` `Duoid`. instance (Duoid.Normal a) => Normal ((,) a)++instance (Duoid a, Duoid b) => Applicative (Parallel ((,,) a b)) where+ pure = Parallel . (pempty,pempty,)+ liftA2 f (Parallel (a, b, x)) (Parallel (a', b', y)) =+ Parallel (a |-| a', b |-| b', f x y)++instance (Duoid a, Duoid b) => Applicative (Sequential ((,,) a b)) where+ pure = Sequential . (sempty,sempty,)+ liftA2 = Base.liftM2++instance (Duoid a, Duoid b) => Monad (Sequential ((,,) a b)) where+ Sequential (u, v, a) >>= k =+ case k a of Sequential (u', v', b) -> Sequential (u >-> u', v >-> v', b)++-- | A writer is a `Normal` `Duoidal` functor when the writee is a+-- `Duoid.Normal` `Duoid`.+instance (Duoid.Normal a, Duoid.Normal b) => Normal ((,,) a b)++instance+ (Duoid a, Duoid b, Duoid c) =>+ Applicative (Parallel ((,,,) a b c))+ where+ pure = Parallel . (pempty,pempty,pempty,)+ liftA2 f (Parallel (a, b, c, x)) (Parallel (a', b', c', y)) =+ Parallel (a |-| a', b |-| b', c |-| c', f x y)++instance+ (Duoid a, Duoid b, Duoid c) =>+ Applicative (Sequential ((,,,) a b c))+ where+ pure = Sequential . (sempty,sempty,sempty,)+ liftA2 = Base.liftM2++instance (Duoid a, Duoid b, Duoid c) => Monad (Sequential ((,,,) a b c)) where+ Sequential (u, v, w, a) >>= k =+ case k a of+ Sequential (u', v', w', b) -> Sequential (u >-> u', v >-> v', w >-> w', b)++-- | A writer is a `Normal` `Duoidal` functor when the writee is a+-- `Duoid.Normal` `Duoid`.+instance+ (Duoid.Normal a, Duoid.Normal b, Duoid.Normal c) =>+ Normal ((,,,) a b c)