packages feed

contravariant 1.4 → 1.4.1

raw patch · 7 files changed

+404/−104 lines, 7 filesnew-uploaderPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.Functor.Contravariant: instance Data.Functor.Contravariant.Contravariant (Control.Applicative.Const a)
- Data.Functor.Contravariant.Divisible: instance GHC.Base.Monoid m => Data.Functor.Contravariant.Divisible.Divisible (Control.Applicative.Const m)
- Data.Functor.Contravariant.Generic: instance (Data.Functor.Contravariant.Generic.GDeciding q f, Data.Functor.Contravariant.Generic.GDeciding q g) => Data.Functor.Contravariant.Generic.GDeciding q (f GHC.Generics.:*: g)
- Data.Functor.Contravariant.Generic: instance (Data.Functor.Contravariant.Generic.GDeciding q f, Data.Functor.Contravariant.Generic.GDeciding q g) => Data.Functor.Contravariant.Generic.GDeciding q (f GHC.Generics.:+: g)
- Data.Functor.Contravariant.Generic: instance Data.Functor.Contravariant.Generic.GDeciding q f => Data.Functor.Contravariant.Generic.GDeciding q (GHC.Generics.M1 i c f)
+ Data.Functor.Contravariant: instance Data.Functor.Contravariant.Contravariant (Data.Functor.Const.Const a)
+ Data.Functor.Contravariant: instance Data.Semigroup.Semigroup (Data.Functor.Contravariant.Predicate a)
+ Data.Functor.Contravariant: instance GHC.Base.Monoid (Data.Functor.Contravariant.Predicate a)
+ Data.Functor.Contravariant.Divisible: instance Data.Functor.Contravariant.Divisible.Decidable Data.StateVar.SettableStateVar
+ Data.Functor.Contravariant.Divisible: instance Data.Functor.Contravariant.Divisible.Divisible Data.StateVar.SettableStateVar
+ Data.Functor.Contravariant.Divisible: instance GHC.Base.Monoid m => Data.Functor.Contravariant.Divisible.Divisible (Data.Functor.Const.Const m)
+ Data.Functor.Contravariant.Generic: instance forall k (q :: * -> GHC.Types.Constraint) (f :: k -> *) (g :: k -> *). (Data.Functor.Contravariant.Generic.GDeciding q f, Data.Functor.Contravariant.Generic.GDeciding q g) => Data.Functor.Contravariant.Generic.GDeciding q (f GHC.Generics.:*: g)
+ Data.Functor.Contravariant.Generic: instance forall k (q :: * -> GHC.Types.Constraint) (f :: k -> *) (g :: k -> *). (Data.Functor.Contravariant.Generic.GDeciding q f, Data.Functor.Contravariant.Generic.GDeciding q g) => Data.Functor.Contravariant.Generic.GDeciding q (f GHC.Generics.:+: g)
+ Data.Functor.Contravariant.Generic: instance forall k (q :: * -> GHC.Types.Constraint) (f :: k -> *) i (c :: GHC.Generics.Meta). Data.Functor.Contravariant.Generic.GDeciding q f => Data.Functor.Contravariant.Generic.GDeciding q (GHC.Generics.M1 i c f)

Files

.travis.yml view
@@ -1,62 +1,155 @@-# NB: don't set `language: haskell` here+# This Travis job script has been generated by a script via+#+#   runghc make_travis_yml_2.hs '-o' '.travis.yml' '--irc-channel=irc.freenode.org#haskell-lens' '--no-no-tests-no-bench' '--no-installed' 'cabal.project'+#+# For more information, see https://github.com/hvr/multi-ghc-travis+#+language: c+sudo: false -# See also https://github.com/hvr/multi-ghc-travis for more information-env:- # we have to use CABALVER=1.16 for GHC<7.6 as well, as there's- # no package for earlier cabal versions in the PPA- - GHCVER=7.4.2 CABALVER=1.16- - GHCVER=7.6.3 CABALVER=1.16- - GHCVER=7.8.4 CABALVER=1.18- - GHCVER=7.10.1 CABALVER=1.22- - GHCVER=head CABALVER=1.22+git:+  submodules: false  # whether to recursively clone submodules +notifications:+  irc:+    channels:+      - "irc.freenode.org#haskell-lens"+    skip_join: true+    template:+      - "\x0313contravariant\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"++cache:+  directories:+    - $HOME/.cabal/packages+    - $HOME/.cabal/store++before_cache:+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+  # remove files that are regenerated by 'cabal update'+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.*+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/*.json+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.cache+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/01-index.tar.idx++  - rm -rfv $HOME/.cabal/packages/head.hackage++addons:+  apt:+    packages: &apt_packages+      - ghc-ppa-tools+      - hlint+ matrix:+  include:+    - compiler: "ghc-7.0.4"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [*apt_packages,cabal-install-2.0,ghc-7.0.4], sources: [hvr-ghc]}}+    - compiler: "ghc-7.2.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [*apt_packages,cabal-install-2.0,ghc-7.2.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.4.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [*apt_packages,cabal-install-2.0,ghc-7.4.2], sources: [hvr-ghc]}}+    - compiler: "ghc-7.6.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [*apt_packages,cabal-install-2.0,ghc-7.6.3], sources: [hvr-ghc]}}+    - compiler: "ghc-7.8.4"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [*apt_packages,cabal-install-2.0,ghc-7.8.4], sources: [hvr-ghc]}}+    - compiler: "ghc-7.10.3"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [*apt_packages,cabal-install-2.0,ghc-7.10.3], sources: [hvr-ghc]}}+    - compiler: "ghc-8.0.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [*apt_packages,cabal-install-2.0,ghc-8.0.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.2.2"+    # env: TEST=--disable-tests BENCH=--disable-benchmarks+      addons: {apt: {packages: [*apt_packages,cabal-install-2.0,ghc-8.2.2], sources: [hvr-ghc]}}+    - compiler: "ghc-8.4.1"+      env: GHCHEAD=true+      addons: {apt: {packages: [*apt_packages,cabal-install-head,ghc-8.4.1], sources: [hvr-ghc]}}+    - compiler: "ghc-head"+      env: GHCHEAD=true+      addons: {apt: {packages: [*apt_packages,cabal-install-head,ghc-head], sources: [hvr-ghc]}}+   allow_failures:-   - env: GHCVER=head CABALVER=1.22+    - compiler: "ghc-7.0.4"+    - compiler: "ghc-7.2.2"+    - compiler: "ghc-8.4.1"+    - compiler: "ghc-head" -# Note: the distinction between `before_install` and `install` is not-#       important. before_install:- - travis_retry sudo add-apt-repository -y ppa:hvr/ghc- - travis_retry sudo apt-get update- - travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER- - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH- - cabal --version+  - HC=${CC}+  - HCPKG=${HC/ghc/ghc-pkg}+  - unset CC+  - ROOTDIR=$(pwd)+  - mkdir -p $HOME/.local/bin+  - "PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$HOME/local/bin:$PATH"+  - HCNUMVER=$(( $(${HC} --numeric-version|sed -E 's/([0-9]+)\.([0-9]+)\.([0-9]+).*/\1 * 10000 + \2 * 100 + \3/') ))+  - echo $HCNUMVER  install:- - travis_retry cabal update- - cabal install --only-dependencies- - travis_retry sudo apt-get -q -y install hlint || cabal install hlint+  - cabal --version+  - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+  - BENCH=${BENCH---enable-benchmarks}+  - TEST=${TEST---enable-tests}+  - HADDOCK=${HADDOCK-true}+  - INSTALLED=${INSTALLED-true}+  - GHCHEAD=${GHCHEAD-false}+  - travis_retry cabal update -v+  - "sed -i.bak 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config"+  - rm -fv cabal.project cabal.project.local+  # Overlay Hackage Package Index for GHC HEAD: https://github.com/hvr/head.hackage+  - |+    if $GHCHEAD; then+      sed -i.bak 's/-- allow-newer:.*/allow-newer: *:base, *:template-haskell, *:ghc, *:Cabal/' ${HOME}/.cabal/config -# Here starts the actual work to be performed for the package under-# test; any command which exits with a non-zero exit code causes the-# build to fail.+      echo 'repository head.hackage'                                                        >> ${HOME}/.cabal/config+      echo '   url: http://head.hackage.haskell.org/'                                       >> ${HOME}/.cabal/config+      echo '   secure: True'                                                                >> ${HOME}/.cabal/config+      echo '   root-keys: 07c59cb65787dedfaef5bd5f987ceb5f7e5ebf88b904bbd4c5cbdeb2ff71b740' >> ${HOME}/.cabal/config+      echo '              2e8555dde16ebd8df076f1a8ef13b8f14c66bad8eafefd7d9e37d0ed711821fb' >> ${HOME}/.cabal/config+      echo '              8f79fd2389ab2967354407ec852cbe73f2e8635793ac446d09461ffb99527f6e' >> ${HOME}/.cabal/config+      echo '   key-threshold: 3'                                                            >> ${HOME}/.cabal.config++      cabal new-update head.hackage -v+    fi+  - grep -Ev -- '^\s*--' ${HOME}/.cabal/config | grep -Ev '^\s*$'+  - "printf 'packages: \".\"\\n' > cabal.project"+  - cat cabal.project+  - if [ -f "./configure.ac" ]; then+      (cd "." && autoreconf -i);+    fi+  - rm -f cabal.project.freeze+  - cabal new-build -w ${HC} ${TEST} ${BENCH} --project-file="cabal.project" --dep -j2 all+  - rm -rf "."/.ghc.environment.* "."/dist+  - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)++# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail. script:- # -v2 provides useful information for debugging- - cabal configure -v2+  # test that source-distributions can be generated+  - (cd "." && cabal sdist)+  - mv "."/dist/contravariant-*.tar.gz ${DISTDIR}/+  - cd ${DISTDIR} || false+  - find . -maxdepth 1 -name '*.tar.gz' -exec tar -xvf '{}' \;+  - "printf 'packages: contravariant-*/*.cabal\\n' > cabal.project"+  - cat cabal.project - # this builds all libraries and executables- # (including tests/benchmarks)- - cabal build - # tests that a source-distribution can be generated- - cabal sdist- - hlint src --cpp-define HLINT+  # build & run tests, build benchmarks+  - cabal new-build -w ${HC} ${TEST} ${BENCH} all - # check that the generated source-distribution can be built & installed- - export SRC_TGZ=$(cabal info . | awk '{print $2 ".tar.gz";exit}') ;-   cd dist/;-   if [ -f "$SRC_TGZ" ]; then-      cabal install --force-reinstalls "$SRC_TGZ";-   else-      echo "expected '$SRC_TGZ' not found";-      exit 1;-   fi+  # cabal check+  - (cd contravariant-* && cabal check) -notifications:-  irc:-    channels:-      - "irc.freenode.org#haskell-lens"-    skip_join: true-    template:-      - "\x0313contravariant\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"+  # haddock+  - rm -rf ./dist-newstyle+  - if $HADDOCK; then cabal new-haddock -w ${HC} ${TEST} ${BENCH} all; else echo "Skipping haddock generation";fi++  # hlint+  - (cd contravariant-* && hlint src --cpp-define=HLINT)++# REGENDATA ["-o",".travis.yml","--irc-channel=irc.freenode.org#haskell-lens","--no-no-tests-no-bench","--no-installed","cabal.project"]+# EOF
CHANGELOG.markdown view
@@ -1,3 +1,10 @@+1.4.1 [2018.01.18]+------------------+* Add `Semigroup` and `Monoid` instances for `Predicate`.+* Add lots of documentation explaining `Contravariant`, `Divisible`, and+  `Decidable`.+* Fix some dodgy CPP usage that caused the build to fail on Eta.+ 1.4 --- * Improved the performance of `Deciding` at the cost of downgrading it to `Trustworthy`.@@ -42,6 +49,10 @@ 1.2.0.1 ----- * Fix build on GHC 7.0.4++1.2+-----+* Renamed `Data.Functor.Contravariant.Applicative` to `Data.Functor.Contravariant.Divisible`  1.1.1 -----
HLint.hs view
@@ -1,2 +1,3 @@ ignore "Eta reduce"-+ignore "Use const"+ignore "Use first"
+ README.markdown view
@@ -0,0 +1,17 @@+contravariant+=============++[![Hackage](https://img.shields.io/hackage/v/contravariant.svg)](https://hackage.haskell.org/package/contravariant)+[![Build Status](https://secure.travis-ci.org/ekmett/contravariant.svg?branch=master)](http://travis-ci.org/ekmett/contravariant)++Haskell 98 contravariant functors++Contact Information+-------------------++Contributions and bug reports are welcome!++Please feel free to contact me through github or on the #haskell IRC channel on irc.freenode.net.++-Edward Kmett+
contravariant.cabal view
@@ -1,6 +1,6 @@ name:          contravariant category:      Control, Data-version:       1.4+version:       1.4.1 license:       BSD3 cabal-version: >= 1.6 license-file:  LICENSE@@ -11,11 +11,21 @@ bug-reports:   http://github.com/ekmett/contravariant/issues copyright:     Copyright (C) 2007-2015 Edward A. Kmett synopsis:      Contravariant functors-description:   Contravariant functors+description:   Contravariant functors. build-type:    Simple+tested-with:   GHC == 7.0.4+             , GHC == 7.2.2+             , GHC == 7.4.2+             , GHC == 7.6.3+             , GHC == 7.8.4+             , GHC == 7.10.3+             , GHC == 8.0.2+             , GHC == 8.2.2+             , GHC == 8.4.1 extra-source-files:   .travis.yml   CHANGELOG.markdown+  README.markdown   HLint.hs  source-repository head@@ -56,13 +66,15 @@   build-depends:     base                              < 5,     transformers        >= 0.2 &&     < 0.6,-    transformers-compat >= 0.3 &&     < 1,-    void                >= 0.6 &&     < 1+    transformers-compat >= 0.3 &&     < 1 +  if !impl(ghc >= 7.9)+    build-depends: void >= 0.6 &&     < 1+   if flag(tagged) && !impl(ghc >= 7.7)     build-depends: tagged >= 0.4.4 && < 1 -  if flag(semigroups)+  if flag(semigroups) && !impl(ghc >= 7.11)     build-depends: semigroups >= 0.15.2 && < 1    if flag(StateVar)
src/Data/Functor/Contravariant.hs view
@@ -95,7 +95,7 @@ import Data.Monoid (Monoid(..)) #endif -#ifdef MIN_VERSION_semigroups+#if defined(MIN_VERSION_semigroups) || __GLASGOW_HASKELL__ >= 711 import Data.Semigroup (Semigroup(..)) #endif @@ -118,8 +118,33 @@  import Prelude hiding ((.),id) --- | Any instance should be subject to the following laws:+-- | The class of contravariant functors. --+-- Whereas in Haskell, one can think of a 'Functor' as containing or producing+-- values, a contravariant functor is a functor that can be thought of as+-- /consuming/ values.+--+-- As an example, consider the type of predicate functions  @a -> Bool@. One+-- such predicate might be @negative x = x < 0@, which+-- classifies integers as to whether they are negative. However, given this+-- predicate, we can re-use it in other situations, providing we have a way to+-- map values /to/ integers. For instance, we can use the @negative@ predicate+-- on a person's bank balance to work out if they are currently overdrawn:+--+-- @+-- newtype Predicate a = Predicate { getPredicate :: a -> Bool }+--+-- instance Contravariant Predicate where+--   contramap f (Predicate p) = Predicate (p . f)+--                                          |   `- First, map the input...+--                                          `----- then apply the predicate.+--+-- overdrawn :: Predicate Person+-- overdrawn = contramap personBankBalance negative+-- @+--+-- Any instance should be subject to the following laws:+-- -- > contramap id = id -- > contramap f . contramap g = contramap (g . f) --@@ -137,7 +162,7 @@   (>$) = contramap . const  -- | If 'f' is both 'Functor' and 'Contravariant' then by the time you factor in the laws--- of each of those classes, it can't actually use it's argument in any meaningful capacity.+-- of each of those classes, it can't actually use its argument in any meaningful capacity. -- -- This method is surprisingly useful. Where both instances exist and are lawful we have -- the following laws:@@ -285,6 +310,19 @@ instance Contravariant Predicate where   contramap f g = Predicate $ getPredicate g . f +#if defined(MIN_VERSION_semigroups) || __GLASGOW_HASKELL__ >= 711+instance Semigroup (Predicate a) where+  Predicate p <> Predicate q = Predicate $ \a -> p a && q a+#endif++instance Monoid (Predicate a) where+  mempty = Predicate $ const True+#if defined(MIN_VERSION_semigroups) || __GLASGOW_HASKELL__ >= 711+  mappend = (<>)+#else+  mappend (Predicate p) (Predicate q) = Predicate $ \a -> p a && q a+#endif+ -- | Defines a total ordering on a type as per 'compare' -- -- This condition is not checked by the types. You must ensure that the supplied@@ -299,7 +337,7 @@ instance Contravariant Comparison where   contramap f g = Comparison $ on (getComparison g) f -#ifdef MIN_VERSION_semigroups+#if defined(MIN_VERSION_semigroups) || __GLASGOW_HASKELL__ >= 711 instance Semigroup (Comparison a) where   Comparison p <> Comparison q = Comparison $ mappend p q #endif@@ -344,7 +382,7 @@ instance Contravariant Equivalence where   contramap f g = Equivalence $ on (getEquivalence g) f -#ifdef MIN_VERSION_semigroups+#if defined(MIN_VERSION_semigroups) || __GLASGOW_HASKELL__ >= 711 instance Semigroup (Equivalence a) where   Equivalence p <> Equivalence q = Equivalence $ \a b -> p a b && q a b #endif@@ -375,7 +413,7 @@ instance Contravariant (Op a) where   contramap f g = Op (getOp g . f) -#ifdef MIN_VERSION_semigroups+#if defined(MIN_VERSION_semigroups) || __GLASGOW_HASKELL__ >= 711 instance Semigroup a => Semigroup (Op a b) where   Op p <> Op q = Op $ \a -> p a <> q a #endif
src/Data/Functor/Contravariant/Divisible.hs view
@@ -20,6 +20,15 @@     Divisible(..), divided, conquered, liftD   -- * Contravariant Alternative   , Decidable(..), chosen, lost+  -- * Mathematical definitions+  -- ** Divisible+  -- $divisible++  -- *** A note on 'conquer'+  -- $conquer++  -- ** Decidable+  -- $decidable   ) where  import Control.Applicative@@ -56,7 +65,7 @@ import Data.Proxy #endif -#if MIN_VERSION_StateVar+#ifdef MIN_VERSION_StateVar import Data.StateVar #endif @@ -73,48 +82,73 @@ -- -- A 'Divisible' contravariant functor is the contravariant analogue of 'Applicative'. ----- In denser jargon, a 'Divisible' contravariant functor is a monoid object in the category--- of presheaves from Hask to Hask, equipped with Day convolution mapping the Cartesian--- product of the source to the Cartesian product of the target.+-- Continuing the intuition that 'Contravariant' functors consume input, a 'Divisible'+-- contravariant functor also has the ability to be composed "beside" another contravariant+-- functor. ----- By way of contrast, an 'Applicative' functor can be viewed as a monoid object in the--- category of copresheaves from Hask to Hask, equipped with Day convolution mapping the--- Cartesian product of the source to the Cartesian product of the target.+-- Serializers provide a good example of 'Divisible' contravariant functors. To begin+-- let's start with the type of serializers for specific types: ----- Given the canonical diagonal morphism:+-- @+-- newtype Serializer a = Serializer { runSerializer :: a -> ByteString }+-- @ --+-- This is a contravariant functor:+-- -- @--- delta a = (a,a)+-- instance Contravariant Serializer where+--   contramap f s = Serializer (runSerializer s . f) -- @ ----- @'divide' 'delta'@ should be associative with 'conquer' as a unit+-- That is, given a serializer for @a@ (@s :: Serializer a@), and a way to turn+-- @b@s into @a@s (a mapping @f :: b -> a@), we have a serializer for @b@:+-- @contramap f s :: Serializer b@. --+-- Divisible gives us a way to combine two serializers that focus on different+-- parts of a structure. If we postulate the existance of two primitive+-- serializers - @string :: Serializer String@ and @int :: Serializer Int@, we+-- would like to be able to combine these into a serializer for pairs of+-- @String@s and @Int@s. How can we do this? Simply run both serializer and+-- combine their output!+-- -- @--- 'divide' 'delta' m 'conquer' = m--- 'divide' 'delta' 'conquer' m = m--- 'divide' 'delta' ('divide' 'delta' m n) o = 'divide' 'delta' m ('divide' 'delta' n o)+-- data StringAndInt = StringAndInt String Int+--+-- stringAndInt :: Serializer StringAndInt+-- stringAndInt = Serializer $ \(StringAndInt s i) ->+--   let sBytes = runSerializer string s+--       iBytes = runSerializer int i+--   in sBytes <> iBytes -- @ ----- With more general arguments you'll need to reassociate and project using the monoidal--- structure of the source category. (Here fst and snd are used in lieu of the more restricted--- lambda and rho, but this construction works with just a monoidal category.)+-- 'divide' is a generalization by also taking a 'contramap' like function to+-- split any @a@ into a pair. This conveniently allows you to target fields of+-- a record, for instance, by extracting the values under two fields and+-- combining them into a tuple. --+-- To complete the example, here is how to write @stringAndInt@ using a+-- @Divisible@ instance:+-- -- @--- 'divide' f m 'conquer' = 'contramap' ('fst' . f) m--- 'divide' f 'conquer' m = 'contramap' ('snd' . f) m--- 'divide' f ('divide' g m n) o = 'divide' f' m ('divide' 'id' n o) where---   f' a = case f a of (bc,d) -> case g bc of (b,c) -> (a,(b,c))+-- instance Divisible Serializer where+--   conquer = Serializer (const mempty)+--+--   divide toBC bSerializer cSerializer = Serializer $ \a ->+--     case toBC a of+--       (b, c) ->+--         let bBytes = runSerializer bSerializer b+--             cBytes = runSerializer cSerializer c+--         in bBytes <> cBytes+--+-- stringAndInt :: Serializer StringAndInt+-- stringAndInt =+--   divide (\(StringAndInt s i) -> (s, i)) string int -- @+-- class Contravariant f => Divisible f where   divide  :: (a -> (b, c)) -> f b -> f c -> f a-  -- | The underlying theory would suggest that this should be:-  ---  -- @-  -- conquer :: (a -> ()) -> f a-  -- @-  ---  -- However, as we are working over a Cartesian category (Hask) and the Cartesian product, such an input-  -- morphism is uniquely determined to be @'const' 'mempty'@, so we elide it.++  -- | Conquer acts as an identity for combining @Divisible@ functors.   conquer :: f a  -- |@@ -280,7 +314,7 @@   conquer = Proxy #endif -#if MIN_VERSION_StateVar+#ifdef MIN_VERSION_StateVar instance Divisible SettableStateVar where   divide k (SettableStateVar l) (SettableStateVar r) = SettableStateVar $ \ a -> case k a of     (b, c) -> l b >> r c@@ -302,26 +336,58 @@ -- * Contravariant Alternative -------------------------------------------------------------------------------- --- |+-- | A 'Decidable' contravariant functor is the contravariant analogue of 'Alternative'. ----- A 'Divisible' contravariant functor is a monoid object in the category of presheaves--- from Hask to Hask, equipped with Day convolution mapping the cartesian product of the--- source to the Cartesian product of the target.+-- Noting the superclass constraint that @f@ must also be 'Divisible', a @Decidable@+-- functor has the ability to "fan out" input, under the intuition that contravariant+-- functors consume input. --+-- In the dicussion for @Divisible@, an example was demonstrated with @Serializer@s,+-- that turn @a@s into @ByteString@s. @Divisible@ allowed us to serialize the /product/+-- of multiple values by concatenation. By making our @Serializer@ also @Decidable@-+-- we now have the ability to serialize the /sum/ of multiple values - for example+-- different constructors in an ADT.+--+-- Consider serializing arbitrary identifiers that can be either @String@s or @Int@s:+-- -- @--- 'choose' 'Left' m ('lose' f)  = m--- 'choose' 'Right' ('lose' f) m = m--- 'choose' f ('choose' g m n) o = 'divide' f' m ('divide' 'id' n o) where---   f' bcd = 'either' ('either' 'id' ('Right' . 'Left') . g) ('Right' . 'Right') . f+-- data Identifier = StringId String | IntId Int -- @ ----- In addition, we expect the same kind of distributive law as is satisfied by the usual--- covariant 'Alternative', w.r.t 'Applicative', which should be fully formulated and--- added here at some point!-+-- We know we have serializers for @String@s and @Int@s, but how do we combine them+-- into a @Serializer@ for @Identifier@? Essentially, our @Serializer@ needs to+-- scrutinise the incoming value and choose how to serialize it:+--+-- @+-- identifier :: Serializer Identifier+-- identifier = Serializer $ \identifier ->+--   case identifier of+--     StringId s -> runSerializer string s+--     IntId i -> runSerializer int i+-- @+--+-- It is exactly this notion of choice that @Decidable@ encodes. Hence if we add+-- an instance of @Decidable@ for @Serializer@...+--+-- @+-- instance Decidable Serializer where+--   lose f = Serializer $ \a -> absurd (f a)+--   choose split l r = Serializer $ \a ->+--     either (runSerializer l) (runSerializer r) (split a)+-- @+--+-- Then our @identifier@ @Serializer@ is+--+-- @+-- identifier :: Serializer Identifier+-- identifier = choose toEither string int where+--   toEither (StringId s) = Left s+--   toEither (IntId i) = Right i+-- @ class Divisible f => Decidable f where-  -- | The only way to win is not to play.+  -- | Acts as identity to 'choose'.   lose :: (a -> Void) -> f a+   choose :: (a -> Either b c) -> f b -> f c -> f a  -- |@@ -483,10 +549,72 @@   choose _ Proxy Proxy = Proxy #endif -#if MIN_VERSION_StateVar-instance Decidable SettableVar where+#ifdef MIN_VERSION_StateVar+instance Decidable SettableStateVar where   lose k = SettableStateVar (absurd . k)   choose k (SettableStateVar l) (SettableStateVar r) = SettableStateVar $ \ a -> case k a of     Left b -> l b     Right c -> r c #endif++-- $divisible+--+-- In denser jargon, a 'Divisible' contravariant functor is a monoid object in the category+-- of presheaves from Hask to Hask, equipped with Day convolution mapping the Cartesian+-- product of the source to the Cartesian product of the target.+--+-- By way of contrast, an 'Applicative' functor can be viewed as a monoid object in the+-- category of copresheaves from Hask to Hask, equipped with Day convolution mapping the+-- Cartesian product of the source to the Cartesian product of the target.+--+-- Given the canonical diagonal morphism:+--+-- @+-- delta a = (a,a)+-- @+--+-- @'divide' 'delta'@ should be associative with 'conquer' as a unit+--+-- @+-- 'divide' 'delta' m 'conquer' = m+-- 'divide' 'delta' 'conquer' m = m+-- 'divide' 'delta' ('divide' 'delta' m n) o = 'divide' 'delta' m ('divide' 'delta' n o)+-- @+--+-- With more general arguments you'll need to reassociate and project using the monoidal+-- structure of the source category. (Here fst and snd are used in lieu of the more restricted+-- lambda and rho, but this construction works with just a monoidal category.)+--+-- @+-- 'divide' f m 'conquer' = 'contramap' ('fst' . f) m+-- 'divide' f 'conquer' m = 'contramap' ('snd' . f) m+-- 'divide' f ('divide' g m n) o = 'divide' f' m ('divide' 'id' n o) where+--   f' a = case f a of (bc,d) -> case g bc of (b,c) -> (a,(b,c))+-- @++-- $conquer+-- The underlying theory would suggest that this should be:+--+-- @+-- conquer :: (a -> ()) -> f a+-- @+--+-- However, as we are working over a Cartesian category (Hask) and the Cartesian product, such an input+-- morphism is uniquely determined to be @'const' 'mempty'@, so we elide it.++-- $decidable+--+-- A 'Divisible' contravariant functor is a monoid object in the category of presheaves+-- from Hask to Hask, equipped with Day convolution mapping the cartesian product of the+-- source to the Cartesian product of the target.+--+-- @+-- 'choose' 'Left' m ('lose' f)  = m+-- 'choose' 'Right' ('lose' f) m = m+-- 'choose' f ('choose' g m n) o = 'divide' f' m ('divide' 'id' n o) where+--   f' bcd = 'either' ('either' 'id' ('Right' . 'Left') . g) ('Right' . 'Right') . f+-- @+--+-- In addition, we expect the same kind of distributive law as is satisfied by the usual+-- covariant 'Alternative', w.r.t 'Applicative', which should be fully formulated and+-- added here at some point!