bound 2.0.1 → 2.0.2
raw patch · 12 files changed
+438/−166 lines, 12 filesdep +th-abstractiondep ~basedep ~template-haskellPVP ok
version bump matches the API change (PVP)
Dependencies added: th-abstraction
Dependency ranges changed: base, template-haskell
API changes (from Hackage documentation)
Files
- .gitignore +18/−0
- .travis.yml +155/−81
- CHANGELOG.markdown +4/−0
- bound.cabal +35/−22
- doc/BoundLaws.hs +102/−0
- doc/LICENSE +30/−0
- doc/bound-laws.cabal +42/−0
- examples/Deriving.hs +1/−1
- examples/Imperative.hs +39/−39
- examples/Overkill.hs +1/−1
- src/Bound/Scope/Simple.hs +0/−4
- src/Bound/TH.hs +11/−18
.gitignore view
@@ -12,3 +12,21 @@ *.hi *~ *#+.stack-work/+cabal-dev+*.chi+*.chs.h+*.dyn_o+*.dyn_hi+.hpc+.hsenv+.cabal-sandbox/+cabal.sandbox.config+*.prof+*.aux+*.hp+*.eventlog+cabal.project.local+cabal.project.local~+.HTF/+.ghc.environment.*
.travis.yml view
@@ -1,99 +1,173 @@ # This Travis job script has been generated by a script via #-# make_travis_yml_2.hs 'bound.cabal'+# haskell-ci '--output=.travis.yml' '--config=cabal.haskell-ci' 'cabal.project' #-# For more information, see https://github.com/hvr/multi-ghc-travis+# To regenerate the script (for example after adjusting tested-with) run #+# haskell-ci regenerate+#+# For more information, see https://github.com/haskell-CI/haskell-ci+#+# version: 0.10+#+version: ~> 1.0 language: c-sudo: false-+os: linux+dist: xenial git:- submodules: false # whether to recursively clone submodules-+ # whether to recursively clone submodules+ submodules: false+notifications:+ irc:+ channels:+ - irc.freenode.org#haskell-lens+ skip_join: true+ template:+ - "\x0313bound\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}" cache: directories: - $HOME/.cabal/packages - $HOME/.cabal/store-+ - $HOME/.hlint before_cache:- - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+ - rm -fv $CABALHOME/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--matrix:+ - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*+ - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json+ - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache+ - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar+ - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx+ - rm -rfv $CABALHOME/packages/head.hackage+jobs: include:- - compiler: "ghc-7.4.2"- # env: TEST=--disable-tests BENCH=--disable-benchmarks- addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.4.2], sources: [hvr-ghc]}}- - compiler: "ghc-7.6.3"- # env: TEST=--disable-tests BENCH=--disable-benchmarks- addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.6.3], sources: [hvr-ghc]}}- - compiler: "ghc-7.8.4"- # env: TEST=--disable-tests BENCH=--disable-benchmarks- addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.8.4], sources: [hvr-ghc]}}- - compiler: "ghc-7.10.3"- # env: TEST=--disable-tests BENCH=--disable-benchmarks- addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-7.10.3], sources: [hvr-ghc]}}- - compiler: "ghc-8.0.2"- # env: TEST=--disable-tests BENCH=--disable-benchmarks- addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.0.2], sources: [hvr-ghc]}}- - compiler: "ghc-8.2.1"- # env: TEST=--disable-tests BENCH=--disable-benchmarks- addons: {apt: {packages: [ghc-ppa-tools,cabal-install-head,ghc-8.2.1], sources: [hvr-ghc]}}-+ - compiler: ghc-8.10.1+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.10.1","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-8.8.3+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.8.3","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-8.6.5+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.6.5","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-8.4.4+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.4.4","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-8.2.2+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.2.2","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-8.0.2+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-8.0.2","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-7.10.3+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.10.3","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-7.8.4+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.8.4","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-7.6.3+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.6.3","cabal-install-3.2"]}}+ os: linux+ - compiler: ghc-7.4.2+ addons: {"apt":{"sources":[{"sourceline":"deb http://ppa.launchpad.net/hvr/ghc/ubuntu xenial main","key_url":"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x063dab2bdc0b3f9fcebc378bff3aeacef6f88286"}],"packages":["ghc-7.4.2","cabal-install-3.2"]}}+ os: linux before_install:- - HC=${CC}- - unset CC- - PATH=/opt/ghc/bin:/opt/ghc-ppa-tools/bin:$PATH- - PKGNAME='bound'-+ - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')+ - WITHCOMPILER="-w $HC"+ - HADDOCK=$(echo "/opt/$CC/bin/haddock" | sed 's/-/\//')+ - HCPKG="$HC-pkg"+ - unset CC+ - CABAL=/opt/ghc/bin/cabal+ - CABALHOME=$HOME/.cabal+ - export PATH="$CABALHOME/bin:$PATH"+ - TOP=$(pwd)+ - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"+ - echo $HCNUMVER+ - CABAL="$CABAL -vnormal+nowrap"+ - set -o pipefail+ - TEST=--enable-tests+ - BENCH=--enable-benchmarks+ - HEADHACKAGE=false+ - rm -f $CABALHOME/config+ - |+ echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config+ echo "remote-build-reporting: anonymous" >> $CABALHOME/config+ echo "write-ghc-environment-files: always" >> $CABALHOME/config+ echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config+ echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config+ echo "world-file: $CABALHOME/world" >> $CABALHOME/config+ echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config+ echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config+ echo "installdir: $CABALHOME/bin" >> $CABALHOME/config+ echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config+ echo "store-dir: $CABALHOME/store" >> $CABALHOME/config+ echo "install-dirs user" >> $CABALHOME/config+ echo " prefix: $CABALHOME" >> $CABALHOME/config+ echo "repository hackage.haskell.org" >> $CABALHOME/config+ echo " url: http://hackage.haskell.org/" >> $CABALHOME/config install:- - cabal --version- - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"- - BENCH=${BENCH---enable-benchmarks}- - TEST=${TEST---enable-tests}- - travis_retry cabal update -v- - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config- - rm -fv cabal.project.local- - "echo 'packages: .' > cabal.project"- - rm -f cabal.project.freeze- - cabal new-build -w ${HC} ${TEST} ${BENCH} --dep -j2 all- - cabal new-build -w ${HC} --disable-tests --disable-benchmarks --dep -j2 all--# 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.+ - ${CABAL} --version+ - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"+ - |+ echo "program-default-options" >> $CABALHOME/config+ echo " ghc-options: $GHCJOBS +RTS -M6G -RTS" >> $CABALHOME/config+ - cat $CABALHOME/config+ - rm -fv cabal.project cabal.project.local cabal.project.freeze+ - travis_retry ${CABAL} v2-update -v+ # Generate cabal.project+ - rm -rf cabal.project cabal.project.local cabal.project.freeze+ - touch cabal.project+ - |+ echo "packages: ." >> cabal.project+ echo "packages: ./doc" >> cabal.project+ - if [ $HCNUMVER -ge 80200 ] ; then echo 'package bound' >> cabal.project ; fi+ - "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"+ - if [ $HCNUMVER -ge 80200 ] ; then echo 'package bound-laws' >> cabal.project ; fi+ - "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"+ - |+ - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(bound|bound-laws)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"+ - cat cabal.project || true+ - cat cabal.project.local || true+ - if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi+ - if [ -f "./doc/configure.ac" ]; then (cd "./doc" && autoreconf -i); fi+ - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}+ - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"+ - rm cabal.project.freeze+ - travis_wait 40 ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all script:- - if [ -f configure.ac ]; then autoreconf -i; fi- - rm -rf dist/ .ghc.environment.*- - cabal sdist # test that a source-distribution can be generated- - cd dist/- - SRCTAR=(${PKGNAME}-*.tar.gz)- - SRC_BASENAME="${SRCTAR/%.tar.gz}"- - tar -xvf "./$SRC_BASENAME.tar.gz"- - cd "$SRC_BASENAME/"-## from here on, CWD is inside the extracted source-tarball- - rm -fv cabal.project.local- - "echo 'packages: .' > cabal.project"- # this builds all libraries and executables (without tests/benchmarks)- - rm -f cabal.project.freeze- - cabal new-build -w ${HC} --disable-tests --disable-benchmarks all- # this builds all libraries and executables (including tests/benchmarks)- # - rm -rf ./dist-newstyle-- # build & run tests- - cabal new-build -w ${HC} ${TEST} ${BENCH} all- - if [ "x$TEST" = "x--enable-tests" ]; then cabal new-test -w ${HC} ${TEST} all; fi+ - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)+ # Packaging...+ - ${CABAL} v2-sdist all+ # Unpacking...+ - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/+ - cd ${DISTDIR} || false+ - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;+ - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \;+ - PKGDIR_bound="$(find . -maxdepth 1 -type d -regex '.*/bound-[0-9.]*')"+ - PKGDIR_bound_laws="$(find . -maxdepth 1 -type d -regex '.*/bound-laws-[0-9.]*')"+ # Generate cabal.project+ - rm -rf cabal.project cabal.project.local cabal.project.freeze+ - touch cabal.project+ - |+ echo "packages: ${PKGDIR_bound}" >> cabal.project+ echo "packages: ${PKGDIR_bound_laws}" >> cabal.project+ - if [ $HCNUMVER -ge 80200 ] ; then echo 'package bound' >> cabal.project ; fi+ - "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"+ - if [ $HCNUMVER -ge 80200 ] ; then echo 'package bound-laws' >> cabal.project ; fi+ - "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"+ - |+ - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(bound|bound-laws)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"+ - cat cabal.project || true+ - cat cabal.project.local || true+ # Building with tests and benchmarks...+ # build & run tests, build benchmarks+ - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all+ # Testing...+ - ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all+ # cabal check...+ - (cd ${PKGDIR_bound} && ${CABAL} -vnormal check)+ - (cd ${PKGDIR_bound_laws} && ${CABAL} -vnormal check)+ # haddock...+ - ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all +# REGENDATA ("0.10",["--output=.travis.yml","--config=cabal.haskell-ci","cabal.project"]) # EOF--notifications:- irc:- channels:- - "irc.freenode.org#haskell-lens"- skip_join: true- template:- - "\x0313bound\x0f/\x0306%{branch}\x0f \x0314%{commit}\x0f %{message} \x0302\x1f%{build_url}\x0f"
CHANGELOG.markdown view
@@ -1,3 +1,7 @@+2.0.2 [2020.10.01]+------------------+* Allow building with GHC 9.0.+ 2.0.1 ----- * Add `abstractEither` and `instantiateEither` to `Bound.Scope`, and
bound.cabal view
@@ -1,8 +1,8 @@ name: bound category: Language, Compilers/Interpreters-version: 2.0.1+version: 2.0.2 license: BSD3-cabal-version: >= 1.9.2+cabal-version: >= 1.10 license-file: LICENSE author: Edward A. Kmett maintainer: Edward A. Kmett <ekmett@gmail.com>@@ -38,10 +38,9 @@ .ghci .gitignore .vim.custom- examples/Simple.hs- examples/Deriving.hs- examples/Overkill.hs- tests/doctests.hs+ doc/*.hs+ doc/bound-laws.cabal+ doc/LICENSE travis/cabal-apt-install travis/config README.markdown@@ -54,7 +53,11 @@ GHC==7.8.4, GHC==7.10.3, GHC==8.0.2,- GHC==8.2.1+ GHC==8.2.2,+ GHC==8.4.4,+ GHC==8.6.5,+ GHC==8.8.3,+ GHC==8.10.1 flag template-haskell description:@@ -66,9 +69,9 @@ custom-setup setup-depends:- base >= 4 && <5,+ base >= 4.5 && < 5, Cabal,- cabal-doctest >= 1.0.1 && <1.1+ cabal-doctest >= 1.0.1 && < 1.1 source-repository head type: git@@ -88,22 +91,25 @@ Bound.Var build-depends:- base >= 4 && < 5,+ base >= 4.5 && < 5, bifunctors >= 3 && < 6, binary >= 0.5 && < 0.9, bytes >= 0.4 && < 1, cereal >= 0.3.5.2 && < 0.6, comonad >= 3 && < 6,- hashable >= 1.2.5.0 && < 1.3,+ hashable >= 1.2.5.0 && < 1.4, mmorph >= 1.0 && < 1.2, deepseq >= 1.1 && < 1.5, profunctors >= 3.3 && < 6, template-haskell >= 2.7 && < 3,+ th-abstraction >= 0.4 && < 0.5, transformers >= 0.2 && < 0.6, transformers-compat >= 0.5 && < 1 ghc-options: -Wall -O2 -fspec-constr -fdicts-cheap -funbox-strict-fields + default-language: Haskell2010+ if impl(ghc >=7.4 && < 7.6) build-depends: ghc-prim @@ -117,10 +123,11 @@ buildable: True ghc-options: -Wall -threaded+ default-language: Haskell2010 build-depends:- base,+ base >= 4.5 && < 5, bound,- deriving-compat >=0.3.4 && <0.4,+ deriving-compat >= 0.3.4 && < 0.6, transformers, transformers-compat @@ -128,9 +135,12 @@ type: exitcode-stdio-1.0 main-is: Overkill.hs hs-source-dirs: examples- ghc-options: -Wall -threaded -main-is Overkill+ ghc-options: -Wall -threaded+ if impl(ghc >= 8.6)+ ghc-options: -Wno-star-is-type+ default-language: Haskell2010 build-depends:- base,+ base >= 4.5 && < 5, bound, transformers, transformers-compat,@@ -143,9 +153,10 @@ type: exitcode-stdio-1.0 main-is: Deriving.hs hs-source-dirs: examples- ghc-options: -Wall -threaded -main-is Deriving+ ghc-options: -Wall -threaded+ default-language: Haskell2010 build-depends:- base,+ base >= 4.5 && < 5, bound, transformers, transformers-compat@@ -154,9 +165,10 @@ type: exitcode-stdio-1.0 main-is: Imperative.hs hs-source-dirs: examples- ghc-options: -Wall -threaded -main-is Imperative+ ghc-options: -Wall -threaded+ default-language: Haskell2010 build-depends:- base,+ base >= 4.5 && < 5, bound, transformers, transformers-compat,@@ -167,9 +179,10 @@ main-is: doctests.hs hs-source-dirs: tests ghc-options: -Wall -threaded+ default-language: Haskell2010 build-depends:- base,+ base >= 4.5 && < 5, bound,- doctest >= 0.11.2 && < 0.13,- vector >= 0.9 && < 0.13,+ doctest >= 0.11.2 && < 0.18,+ vector >= 0.9 && < 0.13, void
+ doc/BoundLaws.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE KindSignatures #-}+module BoundLaws where++import Bound.Class+#if !(MIN_VERSION_base(4,8,0))+import Control.Applicative hiding (Const(..))+#endif+import Control.Monad++{-++What laws should Bound have?++We need at least enough to make sure the typical Monad Exp instances are valid.++Let's start by writing some generic Bound instances.++-}++newtype Const x (m :: * -> *) a = Const x++instance Bound (Const x) where+ Const x >>>= _ = Const x+++newtype Identity (m :: * -> *) a = Id (m a)++instance Bound Identity where+ Id ma >>>= f = Id (ma >>= f)+++data Product f g (m :: * -> *) a = f m a :*: g m a++instance (Bound f, Bound g) => Bound (Product f g) where+ (fma :*: gma) >>>= f = (fma >>>= f) :*: (gma >>>= f)+++data Sum f g (m :: * -> *) a = Inl (f m a) | Inr (g m a)++instance (Bound f, Bound g) => Bound (Sum f g) where+ Inl fma >>>= f = Inl (fma >>>= f)+ Inr gma >>>= f = Inr (gma >>>= f)+++{-++Now we can actually write the typical Monad Exp instance generically+(for theory, not practice), since sums and products and all of the+above is plenty enough to specify an AST.++-}++data Exp (f :: (* -> *) -> * -> *) a = Var a | Branch (f (Exp f) a)++instance Bound f => Functor (Exp f) where+ fmap = liftM++instance Bound f => Applicative (Exp f) where+ pure = Var+ (<*>) = ap++instance Bound f => Monad (Exp f) where+ return = Var+ Var a >>= f = f a+ Branch fE >>= f = Branch (fE >>>= f)++{-++Is this valid? Let's go to Agda and try to prove the Monad laws.+++ left-return : ∀ {A B} (x : A)(f : A -> Exp F B) -> (return x >>= f) ≡ f x+ left-return x f = refl++ right-return : ∀ {A}(m : Exp F A) -> (m >>= return) ≡ m+ right-return (Var x) = refl+ right-return (Branch m) = cong Branch {!!}0++ assoc : ∀ {A B C} (m : Exp F A) (k : A -> Exp F B) (h : B -> Exp F C) -> (m >>= (\ x -> k x >>= h)) ≡ ((m >>= k) >>= h)+ assoc (Var x) k h = refl+ assoc (Branch m) k h = cong Branch {!!}1+++So the first one is fine, but we have two holes:++ ?0 : m >>>= return ≡ m+ ?1 : m >>>= (λ x → k x >>= h) ≡ (m >>>= k) >>>= h++But all of the instances above respect these laws, and they are implied by+the current law for monad transformers, we could just make them the+Bound class laws.++Btw these laws correspond to requiring (f m) to be an m-left module for every m [1],+so we'd also get a law-abiding fmap for (f m).+++Bonus: composing pointwise (\m a -> f m (g m a)) would also create a valid Bound+++[1] Modules over Monads and Initial Semantics - http://web.math.unifi.it/users/maggesi/syn.pdf+-}
+ doc/LICENSE view
@@ -0,0 +1,30 @@+Copyright 2012 Edward Kmett++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ doc/bound-laws.cabal view
@@ -0,0 +1,42 @@+name: bound-laws+category: Language, Compilers/Interpreters+version: 0.1+license: BSD3+cabal-version: >= 1.10+license-file: LICENSE+author: Edward A. Kmett+maintainer: Edward A. Kmett <ekmett@gmail.com>+stability: experimental+homepage: http://github.com/ekmett/bound/+bug-reports: http://github.com/ekmett/bound/issues+copyright: Copyright (C) 2012-2013 Edward A. Kmett+synopsis: Making de Bruijn Succ Less+build-type: Simple+description: Some laws for the @Bound@ class++tested-with:+ 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.4,+ GHC==8.6.5,+ GHC==8.8.3,+ GHC==8.10.1++source-repository head+ type: git+ location: git://github.com/ekmett/bound.git++library+ exposed-modules: BoundLaws+ hs-source-dirs: .+ ghc-options: -Wall+ if impl(ghc >= 8.6)+ ghc-options: -Wno-star-is-type+ default-language: Haskell2010+ build-depends:+ base >= 4.5 && < 5,+ bound
examples/Deriving.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE CPP, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}-module Deriving where+module Main where import Data.List import Data.Foldable
examples/Imperative.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable, RankNTypes, ScopedTypeVariables #-}-module Imperative where+module Main where -- It's possible to use bound "sideways" in order to support terms which do not -- have a Monad instance. A typical situation in which this would happen is when@@ -8,7 +8,7 @@ -- statement. import Bound.Class-import Bound.Scope.Simple+import Bound.Scope -- .Simple import Bound.Term import Bound.Var import Control.Applicative@@ -22,14 +22,14 @@ -- PART 1: We want to model a tiny assembly language.--- +-- -- %0 = add 1 2 -- %1 = add %0 %0 -- ret %1--- +-- -- Add binds a fresh variable, and its operands can either be literals or -- previously-bound variables. Ret must be the last instruction.--- +-- -- Operand is monadic, traversable, and satisfies all the other requirements in -- order to be used with bound. But this is not sufficient, since Operand is -- not the whole language: we also need to define Prog, the sequence of@@ -52,13 +52,13 @@ -- variables. But since the Var in Operand cannot be replaced with a Prog, this -- definition is not monadic, and so we cannot manipulate the (Scope () Prog a) -- using bound's functions. This defeats the point of using Scope at all!--- +-- -- data Prog a -- = Ret (Operand a) -- | Add (Operand a) (Operand a) -- (Scope () Prog a) -- one more bound variable, available -- -- in the rest of the program--- +-- -- The sideways trick is to replace the Operand constructor with a (* -> *) type -- parameter. Instantiating this with the real Operand will allow Operand to -- access the same free variables as Prog. But if we instantiate this with@@ -84,36 +84,36 @@ where -- A value of type (Prog (Scope b operand) a) contains operands of type -- (Scope b operand a), on which we can call instantiate1:- -- + -- -- instantiate1 :: operand a -> Scope b operand a -> operand a- -- + -- -- In the function below, (Scope b operand) and operand become o and o', -- and instantiate1 is called f:- -- + -- -- f :: operand v -> o v -> o' v- go :: forall o o' u- . (forall v. operand v -> o v -> o' v)+ go :: forall o o' u. (Monad o, Monad o')+ => (forall v. operand v -> o v -> o' v) -> operand u -> Prog o u -> Prog o' u go f x (Ret o) = Ret (f x o) go f x (Add o1 o2 cc) = Add (f x o1) (f x o2) $ go f' x cc where -- The rest of the program has access to one extra variable:- -- + -- -- cc :: Prog (Scope () (Scope b operand)) a- -- + -- -- In there, the operands have type (Scope () (Scope b operand) a), and -- this time we cannot call instantiate1 because it would instantiate () -- instead of instantiating b. Instead, we create a function f' which -- preserves the outer (Scope ()):- -- + -- -- f' :: operand a -> Scope () (Scope b operand) a -> Scope () operand a -- f' :: operand a -> Scope () o a -> Scope () o' a- -- + -- -- In the recursive call to go, (Scope () (Scope b operand)) and -- (Scope () operand) become o and o', and f' is called f. f' :: operand v -> Scope () o v -> Scope () o' v- f' v = Scope . f (fmap F v) . unscope+ f' v = toScope . f (fmap F v) . fromScope pAbstract1 :: forall operand a. (Applicative operand, Monad operand, Eq a) => a@@ -121,7 +121,7 @@ -> Prog (Scope () operand) a pAbstract1 = go abstract1 where- go :: forall o o' u. Eq u+ go :: forall o o' u. (Eq u, Monad o, Monad o') => (forall v. Eq v => v -> o v -> o' v) -> u -> Prog o u -> Prog o' u go f x (Ret o) = Ret (f x o)@@ -129,7 +129,7 @@ $ go f' x cc where f' :: forall v. Eq v => v -> Scope () o v -> Scope () o' v- f' v = Scope . f (F v) . unscope+ f' v = toScope . f (F v) . fromScope evalOperand :: Operand Void -> Int evalOperand (Lit i) = i@@ -142,7 +142,7 @@ -- $ Add (Var "%0") (Var "%0") $ pAbstract1 "%1" -- $ Ret (Var "%1") -- :}--- +-- -- >>> evalProg prog -- 6 evalProg :: Prog Operand Void -> Int@@ -151,41 +151,41 @@ where result :: Int result = evalOperand o1 + evalOperand o2- + cc' :: Prog Operand Void cc' = pInstantiate1 (Lit result) cc -- PART 2: Here's a slightly more complicated language.--- +-- -- %0 = add 1 2 -- %1 = add %0 %0 -- swp %0 %1 -- ret %1--- +-- -- The new swp command swaps the contents of two variables, so the two arguments -- must be previously-bound variables, they cannot be literals. This time the -- naïve definition looks like this:--- +-- -- data Prog' a -- = Ret' (Operand a) -- | Swp' a a -- (Prog' a) -- | Add' (Operand a) (Operand a) -- (Scope () Prog' a)--- +-- -- If we apply the sideways trick to this definition, the newly-bound variables -- will only be available in the operands, and so it won't be possible to call -- swp on them. The first step towards a solution is to add seemingly-useless -- Identity wrappers:--- +-- -- data Prog' a -- = Ret' (Operand a) -- | Swp' (Identity a) (Identity a) -- (Prog' a) -- | Add' (Operand a) (Operand a) -- (Scope () Prog' a)--- +-- -- We can now apply the sideways trick twice: once for Operand, and once for -- Identity. This gives us a lot of control: we can bind fresh variables which -- can only be used inside the operands, we can bind fresh variables which can@@ -211,8 +211,8 @@ -> Prog' operand identity a pInstantiate1' = go (instantiate1 . pure) (instantiate1 . pure) where- go :: forall o o' i i' u- . (forall v. v -> o v -> o' v)+ go :: forall o o' i i' u. (Monad i, Monad i', Monad o, Monad o')+ => (forall v. v -> o v -> o' v) -> (forall v. v -> i v -> i' v) -> u -> Prog' o i u -> Prog' o' i' u go fo fi x = go'@@ -224,12 +224,12 @@ go' (Add' o1 o2 cc) = Add' (fo x o1) (fo x o2) (go fo' fi' x cc)- + fo' :: v -> Scope () o v -> Scope () o' v- fo' v = Scope . fo (F v) . unscope- + fo' v = toScope . fo (F v) . fromScope+ fi' :: v -> Scope () i v -> Scope () i' v- fi' v = Scope . fi (F v) . unscope+ fi' v = toScope . fi (F v) . fromScope pAbstract1' :: ( Applicative operand, Monad operand , Applicative identity, Monad identity@@ -240,7 +240,7 @@ -> Prog' (Scope () operand) (Scope () identity) a pAbstract1' = go abstract1 abstract1 where- go :: forall o o' i i' u. Eq u+ go :: forall o o' i i' u. (Eq u, Monad i, Monad i', Monad o, Monad o') => (forall v. Eq v => v -> o v -> o' v) -> (forall v. Eq v => v -> i v -> i' v) -> u -> Prog' o i u -> Prog' o' i' u@@ -253,12 +253,12 @@ go' (Add' o1 o2 cc) = Add' (fo x o1) (fo x o2) (go fo' fi' x cc)- + fo' :: Eq v => v -> Scope () o v -> Scope () o' v- fo' v = Scope . fo (F v) . unscope- + fo' v = toScope . fo (F v) . fromScope+ fi' :: Eq v => v -> Scope () i v -> Scope () i' v- fi' v = Scope . fi (F v) . unscope+ fi' v = toScope . fi (F v) . fromScope evalOperand' :: Operand (IORef Int) -> IO Int evalOperand' (Lit i) = return i@@ -272,7 +272,7 @@ -- $ Swp' (Identity "%0") (Identity "%1") -- $ Ret' (Var "%1") -- :}--- +-- -- >>> evalProg' prog' -- 3 evalProg' :: Prog' Operand Identity (IORef Int) -> IO Int
examples/Overkill.hs view
@@ -7,7 +7,7 @@ {-# OPTIONS_GHC -fwarn-incomplete-patterns -fno-warn-orphans #-} -module Overkill where+module Main where -- Dara.Functor.Classes in transformers 0.4.0 are totally different #if MIN_VERSION_transformers(0,5,0) || !MIN_VERSION_transformers(0,4,0)
src/Bound/Scope/Simple.hs view
@@ -170,11 +170,7 @@ {-# INLINE lift #-} instance MFunctor (Scope b) where-#if !MIN_VERSION_base(4,8,0) hoist f = hoistScope f-#else- hoist = hoistScope-#endif {-# INLINE hoist #-} #if (MIN_VERSION_transformers(0,5,0)) || !(MIN_VERSION_transformers(0,4,0))
src/Bound/TH.hs view
@@ -28,6 +28,7 @@ import Control.Monad (foldM, mzero, guard) import Bound.Class (Bound((>>>=))) import Language.Haskell.TH+import Language.Haskell.TH.Datatype.TyVarBndr #if __GLASGOW_HASKELL__ < 710 import Control.Applicative (Applicative, pure, (<*>)) #endif@@ -49,7 +50,7 @@ -- {-\# LANGUAGE TemplateHaskell #-} -- -- import Bound (Scope, makeBound)--- import Data.Functor.Classes (Show1, Read1, shosPrec1, readsPrec1)+-- import Data.Functor.Classes (Show1, Read1, showsPrec1, readsPrec1) -- import Data.Deriving (deriveShow1, deriveRead1) -- -- data Exp a@@ -129,7 +130,7 @@ #endif _ -> fail $ show name ++ " Must be a data type." -makeBound' :: Name -> [TyVarBndr] -> [Con] -> DecsQ+makeBound' :: Name -> [TyVarBndrUnit] -> [Con] -> DecsQ makeBound' name vars cons = do let instanceHead :: Type instanceHead = name `conAppsT` map VarT (typeVars (init vars))@@ -229,11 +230,11 @@ | Variable Name deriving Show -constructBind :: Name -> [TyVarBndr] -> [Con] -> ExpQ+constructBind :: Name -> [TyVarBndrUnit] -> [Con] -> ExpQ constructBind name vars cons = do interpret =<< construct name vars cons -construct :: Name -> [TyVarBndr] -> [Con] -> Q [Components]+construct :: Name -> [TyVarBndrUnit] -> [Con] -> Q [Components] construct name vars constructors = do var <- getPure name vars constructors for constructors $ \con -> do@@ -284,7 +285,7 @@ isKonst :: Type -> Bool isKonst ConT {} = True- isKonst (VarT n) = n /= getName (last vars)+ isKonst (VarT n) = n /= tvName (last vars) isKonst (AppT a b) = isKonst a && isKonst b isKonst _ = False @@ -345,12 +346,8 @@ | otherwise = Just (a `AppT` b) stripLast2 _ = Nothing -getName :: TyVarBndr -> Name-getName (PlainTV name) = name-getName (KindedTV name _) = name- -- Returns candidate-getPure :: Name -> [TyVarBndr] -> [Con] -> Q Name+getPure :: Name -> [TyVarBndrUnit] -> [Con] -> Q Name getPure _name tyvr cons= do let findReturn :: Type -> [(Name, [Type])] -> Name@@ -367,7 +364,7 @@ -- -- lastTyVar = c lastTyVar :: Type- lastTyVar = VarT (last (map getName tyvr))+ lastTyVar = VarT (last (typeVars tyvr)) allTypeArgs :: Con -> (Name, [Type]) allTypeArgs con = case con of@@ -391,13 +388,9 @@ -- Type mangling ------------------------------------------------------------------------------- --- | Extraty type variables-typeVars :: [TyVarBndr] -> [Name]-typeVars = map varBindName--varBindName :: TyVarBndr -> Name-varBindName (PlainTV n) = n-varBindName (KindedTV n _) = n+-- | Extract type variables+typeVars :: [TyVarBndr_ flag] -> [Name]+typeVars = map tvName -- | Apply arguments to a type constructor. conAppsT :: Name -> [Type] -> Type