diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 dist
+dist-*
 docs
 wiki
 TAGS
@@ -11,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.*
diff --git a/.hlint.yaml b/.hlint.yaml
new file mode 100644
--- /dev/null
+++ b/.hlint.yaml
@@ -0,0 +1,4 @@
+- arguments: [--cpp-define=HLINT, --cpp-ansi]
+
+- ignore: {name: Eta reduce}
+- ignore: {name: Use import/export shortcut}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
--- a/.travis.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-language: haskell
-before_install:
-  # Uncomment whenever hackage is down.
-  # - mkdir -p ~/.cabal && cp travis/config ~/.cabal/config && cabal update
-  - cabal update
-
-  # Try installing some of the build-deps with apt-get for speed.
-  - travis/cabal-apt-install $mode
-
-install:
-  - cabal configure -flib-Werror $mode
-  - cabal build
-
-script:
-  - $script && hlint src --cpp-define HLINT
-
-notifications:
-  irc:
-    channels:
-      - "irc.freenode.org#haskell-lens"
-    skip_join: true
-    template:
-      - "\x0313comonad\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"
-
-env:
-  - mode="--enable-tests" script="cabal test --show-details=always"
diff --git a/.vim.custom b/.vim.custom
new file mode 100644
--- /dev/null
+++ b/.vim.custom
@@ -0,0 +1,31 @@
+" Add the following to your .vimrc to automatically load this on startup
+
+" if filereadable(".vim.custom")
+"     so .vim.custom
+" endif
+
+function StripTrailingWhitespace()
+  let myline=line(".")
+  let mycolumn = col(".")
+  silent %s/  *$//
+  call cursor(myline, mycolumn)
+endfunction
+
+" enable syntax highlighting
+syntax on
+
+" search for the tags file anywhere between here and /
+set tags=TAGS;/
+
+" highlight tabs and trailing spaces
+set listchars=tab:‗‗,trail:‗
+set list
+
+" f2 runs hasktags
+map <F2> :exec ":!hasktags -x -c --ignore src"<CR><CR>
+
+" strip trailing whitespace before saving
+" au BufWritePre *.hs,*.markdown silent! cal StripTrailingWhitespace()
+
+" rebuild hasktags after saving
+au BufWritePost *.hs silent! :exec ":!hasktags -x -c --ignore src"
diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,118 @@
+5.0.10 [2026.01.10]
+-------------------
+* Support building with MicroHs.
+* Remove unused `transformers-compat` dependency.
+
+5.0.9 [2024.12.04]
+------------------
+* Drop support for pre-8.0 versions of GHC.
+
+5.0.8 [2020.12.30]
+-----------------
+* Explicitly mark modules as Safe or Trustworthy
+* The build-type has been changed from `Custom` to `Simple`.
+  To achieve this, the `doctests` test suite has been removed in favor of using [`cabal-docspec`](https://github.com/phadej/cabal-extras/tree/master/cabal-docspec) to run the doctests.
+
+5.0.7 [2020.12.15]
+------------------
+* Move `FunctorWithIndex (TracedT m w)` instance from `lens`.
+  This instance depends on the `indexed-traversable` package. This can be disabled using the flag of the same name.
+
+5.0.6 [2019.11.26]
+------------------
+* Achieve forward compatibility with
+  [GHC proposal 229](https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0229-whitespace-bang-patterns.rst).
+
+5.0.5 [2019.05.02]
+------------------
+* Raised the minimum `semigroups` version to 0.16.2. In addition, the
+  package will only be required at all for GHCs before 8.0.
+* Drop the `contravariant` flag from `comonad.cabal`, as `comonad` no longer
+  depends on the `contravariant` library.
+
+5.0.4 [2018.07.01]
+------------------
+* Add `Comonad` instances for `Tagged s` with `s` of any kind. Before the
+  change, `s` had to be of kind `*`.
+* Allow `containers-0.6`.
+
+5.0.3 [2018.02.06]
+------------------
+* Don't enable `Safe` on GHC 7.2.
+
+5.0.2
+-----
+* Support `doctest-0.12`
+
+5.0.1
+-----
+* Revamp `Setup.hs` to use `cabal-doctest`. This makes it build
+  with `Cabal-1.25`, and makes the `doctest`s work with `cabal new-build` and
+  sandboxes.
+
+5
+-
+* Removed module `Data.Functor.Coproduct` in favor of the `transformers`
+  package's `Data.Functor.Sum`. n.b. Compatibility with older versions of
+  `transformers` is possible using `transformers-compat`.
+* Add `Comonad` instance for `Data.Functor.Sum.Sum`
+* GHC 8 compatibility
+
+4.2.7.2
+-------
+* Compiles warning-free on GHC 7.10
+
+4.2.7.1
+-------
+* Use CPP
+
+4.2.7
+-----
+* `Trustworthy` fixes for GHC 7.2
+
+4.2.6
+-----
+* Re-export `(Data.Functor.$>)` rather than supply our own on GHC 7.8+
+* Better SafeHaskell support.
+* `instance Monoid m => ComonadTraced m ((->) m)`
+
+4.2.5
+-------
+* Added a `MINIMAL` pragma to `Comonad`.
+* Added `DefaultSignatures` support for `ComonadApply` on GHC 7.2+
+
+4.2.4
+-----
+* Added Kenneth Foner's fixed point as `kfix`.
+
+4.2.3
+-----
+* Add `Comonad` and `ComonadEnv` instances for `Arg e` from `semigroups 0.16.3` which can be used to extract the argmin or argmax.
+
+4.2.2
+-----
+* `contravariant` 1.0 support
+
+4.2.1
+-----
+* Added flags that supply unsupported build modes that can be convenient for sandbox users.
+
+4.2
+---
+* `transformers 0.4` compatibility
+
+4.1
+---
+* Fixed the 'Typeable' instance for 'Cokleisli on GHC 7.8.1
+
+4.0.1
+-----
+* Fixes to avoid warnings on GHC 7.8.1
+
+4.0
+---
+* Merged the contents of `comonad-transformers` and `comonads-fd` into this package.
+
 3.1
 ---
 * Added `instance Comonad (Tagged s)`.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright 2008-2013 Edward Kmett
+Copyright 2008-2014 Edward Kmett
 Copyright 2004-2008 Dave Menendez
 
 All rights reserved.
@@ -13,10 +13,6 @@
 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
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -1,9 +1,10 @@
 comonad
 =======
 
-[![Build Status](https://secure.travis-ci.org/ekmett/comonad.png?branch=master)](http://travis-ci.org/ekmett/comonad)
+[![Build Status](https://github.com/ekmett/comonad/workflows/Haskell-CI/badge.svg)](https://github.com/ekmett/comonad/actions?query=workflow%3AHaskell-CI)
 
-This package provides comonads, the categorical dual of monads.
+This package provides comonads, the categorical dual of monads. The typeclass
+provides three methods:  `extract`, `duplicate`, and `extend`.
 
     class Functor w => Comonad w where
         extract :: w a -> a
@@ -12,42 +13,42 @@
 
 There are two ways to define a comonad:
 
-I. Provide definitions for 'extract' and 'extend' satisfying these laws:
+I. Provide definitions for `extract` and `extend` satisfying these laws:
 
     extend extract      = id
     extract . extend f  = f
     extend f . extend g = extend (f . extend g)
 
-In this case, you may simply set 'fmap' = 'liftW'.
+In this case, you may simply set `fmap` = `liftW`.
 
-These laws are directly analogous to the laws for monads
-and perhaps can be made clearer by viewing them as laws stating
-that Cokleisli composition must be associative, and has extract for
-a unit:
+These laws are directly analogous to the [laws for
+monads](https://wiki.haskell.org/Monad_laws). The comonad laws can
+perhaps be made clearer by viewing them as stating that Cokleisli composition
+must be a) associative and b) have `extract` for a unit:
 
     f =>= extract   = f
     extract =>= f   = f
     (f =>= g) =>= h = f =>= (g =>= h)
 
-II. Alternately, you may choose to provide definitions for 'fmap',
-'extract', and 'duplicate' satisfying these laws:
+II. Alternately, you may choose to provide definitions for `fmap`,
+`extract`, and `duplicate` satisfying these laws:
 
     extract . duplicate      = id
     fmap extract . duplicate = id
     duplicate . duplicate    = fmap duplicate . duplicate
 
-In this case you may not rely on the ability to define 'fmap' in
-terms of 'liftW'.
+In this case, you may not rely on the ability to define `fmap` in
+terms of `liftW`.
 
-You may of course, choose to define both 'duplicate' /and/ 'extend'.
-In that case you must also satisfy these laws:
+You may, of course, choose to define both `duplicate` _and_ `extend`.
+In that case, you must also satisfy these laws:
 
     extend f  = fmap f . duplicate
     duplicate = extend id
     fmap f    = extend (f . extract)
 
-These are the default definitions of 'extend' and'duplicate' and
-the definition of 'liftW' respectively.
+These implementations are the default definitions of `extend` and`duplicate` and
+the definition of `liftW` respectively.
 
 Contact Information
 -------------------
diff --git a/Setup.lhs b/Setup.lhs
--- a/Setup.lhs
+++ b/Setup.lhs
@@ -1,55 +1,6 @@
-#!/usr/bin/runhaskell
 \begin{code}
-{-# OPTIONS_GHC -Wall #-}
 module Main (main) where
-
-import Data.List ( nub )
-import Data.Version ( showVersion )
-import Distribution.Package ( PackageName(PackageName), Package, PackageId, InstalledPackageId, packageVersion, packageName )
-import Distribution.PackageDescription ( PackageDescription(), TestSuite(..) )
-import Distribution.Simple ( defaultMainWithHooks, UserHooks(..), simpleUserHooks )
-import Distribution.Simple.Utils ( rewriteFile, createDirectoryIfMissingVerbose, copyFiles )
-import Distribution.Simple.BuildPaths ( autogenModulesDir )
-import Distribution.Simple.Setup ( BuildFlags(buildVerbosity), Flag(..), fromFlag, HaddockFlags(haddockDistPref))
-import Distribution.Simple.LocalBuildInfo ( withLibLBI, withTestLBI, LocalBuildInfo(), ComponentLocalBuildInfo(componentPackageDeps) )
-import Distribution.Text ( display )
-import Distribution.Verbosity ( Verbosity, normal )
-import System.FilePath ( (</>) )
-
+import Distribution.Simple (defaultMain)
 main :: IO ()
-main = defaultMainWithHooks simpleUserHooks
-  { buildHook = \pkg lbi hooks flags -> do
-     generateBuildModule (fromFlag (buildVerbosity flags)) pkg lbi
-     buildHook simpleUserHooks pkg lbi hooks flags
-  , postHaddock = \args flags pkg lbi -> do
-     copyFiles normal (haddockOutputDir flags pkg) []
-     postHaddock simpleUserHooks args flags pkg lbi
-  }
-
-haddockOutputDir :: Package p => HaddockFlags -> p -> FilePath
-haddockOutputDir flags pkg = destDir where
-  baseDir = case haddockDistPref flags of
-    NoFlag -> "."
-    Flag x -> x
-  destDir = baseDir </> "doc" </> "html" </> display (packageName pkg)
-
-generateBuildModule :: Verbosity -> PackageDescription -> LocalBuildInfo -> IO ()
-generateBuildModule verbosity pkg lbi = do
-  let dir = autogenModulesDir lbi
-  createDirectoryIfMissingVerbose verbosity True dir
-  withLibLBI pkg lbi $ \_ libcfg -> do
-    withTestLBI pkg lbi $ \suite suitecfg -> do
-      rewriteFile (dir </> "Build_" ++ testName suite ++ ".hs") $ unlines
-        [ "module Build_" ++ testName suite ++ " where"
-        , "deps :: [String]"
-        , "deps = " ++ (show $ formatdeps (testDeps libcfg suitecfg))
-        ]
-  where
-    formatdeps = map (formatone . snd)
-    formatone p = case packageName p of
-      PackageName n -> n ++ "-" ++ showVersion (packageVersion p)
-
-testDeps :: ComponentLocalBuildInfo -> ComponentLocalBuildInfo -> [(InstalledPackageId, PackageId)]
-testDeps xs ys = nub $ componentPackageDeps xs ++ componentPackageDeps ys
-
+main = defaultMain
 \end{code}
diff --git a/comonad.cabal b/comonad.cabal
--- a/comonad.cabal
+++ b/comonad.cabal
@@ -1,6 +1,6 @@
 name:          comonad
 category:      Control, Comonads
-version:       3.1
+version:       5.0.10
 license:       BSD3
 cabal-version: >= 1.10
 license-file:  LICENSE
@@ -9,60 +9,114 @@
 stability:     provisional
 homepage:      http://github.com/ekmett/comonad/
 bug-reports:   http://github.com/ekmett/comonad/issues
-copyright:     Copyright (C) 2008-2013 Edward A. Kmett,
+copyright:     Copyright (C) 2008-2014 Edward A. Kmett,
                Copyright (C) 2004-2008 Dave Menendez
-synopsis:      Haskell 98 compatible comonads
-description:   Haskell 98 compatible comonads
-build-type:    Custom
+synopsis:      Comonads
+description:   Comonads.
+build-type:    Simple
+tested-with:   GHC == 8.0.2
+             , GHC == 8.2.2
+             , GHC == 8.4.4
+             , GHC == 8.6.5
+             , GHC == 8.8.4
+             , GHC == 8.10.7
+             , GHC == 9.0.2
+             , GHC == 9.2.8
+             , GHC == 9.4.8
+             , GHC == 9.6.7
+             , GHC == 9.8.4
+             , GHC == 9.10.3
+             , GHC == 9.12.2
+             , GHC == 9.14.1
 extra-source-files:
   .gitignore
-  .travis.yml
+  .hlint.yaml
+  .vim.custom
+  coq/Store.v
   README.markdown
   CHANGELOG.markdown
   examples/History.hs
 
--- You can disable the doctests test suite with -f-test-doctests
-flag test-doctests
+flag containers
+  description:
+    You can disable the use of the `containers` package using `-f-containers`.
+    .
+    Disabing this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users.
   default: True
   manual: True
 
+flag distributive
+  description:
+    You can disable the use of the `distributive` package using `-f-distributive`.
+    .
+    Disabling this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users.
+    .
+    If disabled we will not supply instances of `Distributive`
+    .
+  default: True
+  manual: True
+
+flag indexed-traversable
+  description:
+    You can disable the use of the `indexed-traversable` package using `-f-indexed-traversable`.
+    .
+    Disabling this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users.
+    .
+    If disabled we will not supply instances of `FunctorWithIndex`
+    .
+  default: True
+  manual: True
+
+
 source-repository head
   type: git
-  location: git://github.com/ekmett/comonad.git
+  location: https://github.com/ekmett/comonad.git
 
 library
   hs-source-dirs: src
   default-language: Haskell2010
-  other-extensions: CPP
+  ghc-options: -Wall
 
   build-depends:
-    base         >= 4       && < 5,
-    transformers >= 0.2     && < 0.4,
-    containers   >= 0.3     && < 0.6,
-    semigroups   >= 0.8.3   && < 1,
-    tagged       >= 0.1     && < 1
+    base                >= 4.9 && < 5,
+    tagged              >= 0.8.6.1 && < 1,
+    transformers        >= 0.5 && < 0.7
 
-  exposed-modules:
-    Control.Comonad
+  if flag(containers)
+    build-depends: containers >= 0.3 && < 0.9
 
-  ghc-options: -Wall
+  if flag(distributive)
+    build-depends: distributive >= 0.5.2 && < 1
 
-test-suite doctests
-  type:           exitcode-stdio-1.0
-  default-language: Haskell2010
-  main-is:        doctests.hs
-  ghc-options:    -Wall -threaded
-  hs-source-dirs: tests
+  if flag(indexed-traversable)
+    build-depends: indexed-traversable >= 0.1.1 && < 0.2
 
-  if !flag(test-doctests)
-    buildable: False
-  else
-    build-depends:
-      base,
-      directory      >= 1.0,
-      doctest        >= 0.9.1,
-      filepath
+  if impl(ghc >= 9.0)
+    -- these flags may abort compilation with GHC-8.10
+    -- https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3295
+    ghc-options: -Winferred-safe-imports -Wmissing-safe-haskell-mode
 
-  if impl(ghc<7.6.1)
-    ghc-options: -Werror
+  exposed-modules:
+    Control.Comonad
+    Control.Comonad.Env
+    Control.Comonad.Env.Class
+    Control.Comonad.Hoist.Class
+    Control.Comonad.Identity
+    Control.Comonad.Store
+    Control.Comonad.Store.Class
+    Control.Comonad.Traced
+    Control.Comonad.Traced.Class
+    Control.Comonad.Trans.Class
+    Control.Comonad.Trans.Env
+    Control.Comonad.Trans.Identity
+    Control.Comonad.Trans.Store
+    Control.Comonad.Trans.Traced
+    Data.Functor.Composition
 
+  other-extensions:
+    CPP
+    RankNTypes
+    MultiParamTypeClasses
+    FunctionalDependencies
+    FlexibleInstances
+    UndecidableInstances
diff --git a/coq/Store.v b/coq/Store.v
new file mode 100644
--- /dev/null
+++ b/coq/Store.v
@@ -0,0 +1,96 @@
+(* Proof StoreT forms a comonad -- Russell O'Connor *)
+
+Set Implict Arguments.
+Unset Strict Implicit.
+
+Require Import FunctionalExtensionality.
+
+Record Comonad (w : Type -> Type) : Type :=
+ { extract : forall a, w a -> a
+ ; extend : forall a b, (w a -> b) -> w a -> w b
+ ; law1 : forall a x, extend _ _ (extract a) x = x
+ ; law2 : forall a b f x, extract b (extend a _ f x) = f x
+ ; law3 : forall a b c f g x, extend b c f (extend a b g x) = extend a c (fun y => f (extend a b g y)) x
+ }.
+
+Section StoreT.
+
+Variables (s : Type) (w:Type -> Type).
+Hypothesis wH : Comonad w.
+
+Definition map a b f x := extend _ wH a b (fun y => f (extract _ wH _ y)) x.
+
+Lemma map_extend : forall a b c f g x, map b c f (extend _ wH a b g x) = extend _ wH _ _ (fun y => f (g y)) x.
+Proof.
+intros a b c f g x.
+unfold map.
+rewrite law3.
+apply equal_f.
+apply f_equal.
+extensionality y.
+rewrite law2.
+reflexivity.
+Qed.
+
+Record StoreT (a:Type): Type := mkStoreT
+  {store : w (s -> a)
+  ;loc   : s}.
+
+Definition extractST a (x:StoreT a) : a := 
+ extract _ wH _ (store _ x) (loc _ x).
+
+Definition mapST a b (f:a -> b) (x:StoreT a) : StoreT b :=
+ mkStoreT _ (map _ _ (fun g x => f (g x)) (store _ x)) (loc _ x).
+
+Definition duplicateST a (x:StoreT a) : StoreT (StoreT a) :=
+ mkStoreT _ (extend _ wH _ _ (mkStoreT _) (store _ x)) (loc _ x).
+
+Let extendST := fun a b f x => mapST _ b f (duplicateST a x).
+
+Lemma law1ST : forall a x, extendST _ _ (extractST a) x = x.
+Proof.
+intros a [v b].
+unfold extractST, extendST, duplicateST, mapST.
+simpl.
+rewrite map_extend.
+simpl.
+replace (fun (y : w (s -> a)) (x : s) => extract w wH (s -> a) y x)
+ with (extract w wH (s -> a)).
+ rewrite law1.
+ reflexivity.
+extensionality y.
+extensionality x.
+reflexivity.
+Qed.
+
+Lemma law2ST : forall a b f x, extractST b (extendST a _ f x) = f x.
+Proof.
+intros a b f [v c].
+unfold extendST, mapST, extractST.
+simpl.
+rewrite map_extend.
+rewrite law2.
+reflexivity.
+Qed.
+
+Lemma law3ST : forall a b c f g x, extendST b c f (extendST a b g x) = extendST a c (fun y => f (extendST a b g y)) x.
+Proof.
+intros a b c f g [v d].
+unfold extendST, mapST, extractST.
+simpl.
+repeat rewrite map_extend.
+rewrite law3.
+repeat (apply equal_f||apply f_equal).
+extensionality y.
+extensionality x.
+rewrite map_extend.
+reflexivity.
+Qed.
+
+Definition StoreTComonad : Comonad StoreT :=
+ Build_Comonad _ _ _ law1ST law2ST law3ST.
+
+End StoreT.
+
+Check StoreTComonad.
+
diff --git a/examples/History.hs b/examples/History.hs
--- a/examples/History.hs
+++ b/examples/History.hs
@@ -2,12 +2,13 @@
 {-# OPTIONS_GHC -Wall #-}
 
 -- http://www.mail-archive.com/haskell@haskell.org/msg17244.html
+module History where
 
-import Prelude hiding (id,(.),sum)
 import Control.Category
 import Control.Comonad
 import Data.Foldable hiding (sum)
 import Data.Traversable
+import Prelude hiding (id,(.),sum)
 
 infixl 4 :>
 
@@ -51,7 +52,7 @@
 ini dx = extract dx `fby` extend ini dx
 
 fibo :: Num b => History a -> b
-fibo d = wfix $ d $> fby 0 . extend (\dfibo -> extract dfibo + fby 1 dfibo) 
+fibo d = wfix $ d $> fby 0 . extend (\dfibo -> extract dfibo + fby 1 dfibo)
 
 fibo' :: Num b => History a -> b
 fibo' d = fst $ wfix $ d $> fby (0, 1) . fmap (\(x, x') -> (x',x+x'))
diff --git a/src/Control/Comonad.hs b/src/Control/Comonad.hs
--- a/src/Control/Comonad.hs
+++ b/src/Control/Comonad.hs
@@ -1,15 +1,12 @@
 {-# LANGUAGE CPP #-}
-#ifdef __GLASGOW_HASKELL__
-#if __GLASGOW_HASKELL__ >= 707
-{-# LANGUAGE DeriveDataTypeable, StandaloneDeriving, Safe #-}
-#elif __GLASGOW_HASKELL__ >= 702
-{-# LANGUAGE Trustworthy #-}
-#endif
-#endif
+{-# LANGUAGE DefaultSignatures #-}
+{-# LANGUAGE Safe #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE PolyKinds #-}
  -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Comonad
--- Copyright   :  (C) 2008-2012 Edward Kmett,
+-- Copyright   :  (C) 2008-2015 Edward Kmett,
 --                (C) 2004 Dave Menendez
 -- License     :  BSD-style (see the file LICENSE)
 --
@@ -24,6 +21,7 @@
   , liftW     -- :: Comonad w => (a -> b) -> w a -> w b
   , wfix      -- :: Comonad w => w (w a -> a) -> a
   , cfix      -- :: Comonad w => (w a -> a) -> w a
+  , kfix      -- :: ComonadApply w => w (w a -> a) -> w a
   , (=>=)
   , (=<=)
   , (<<=)
@@ -42,30 +40,25 @@
   ) where
 
 -- import _everything_
+import Data.Functor
 import Control.Applicative
 import Control.Arrow
 import Control.Category
 import Control.Monad (ap)
-#if MIN_VERSION_base(4,7,0)
--- Control.Monad.Instances is empty
-#else
-import Control.Monad.Instances
-#endif
 import Control.Monad.Trans.Identity
 import Data.Functor.Identity
+import qualified Data.Functor.Sum as FSum
 import Data.List.NonEmpty hiding (map)
 import Data.Semigroup hiding (Product)
 import Data.Tagged
-import Data.Tree
 import Prelude hiding (id, (.))
 import Control.Monad.Fix
-#if __GLASGOW_HASKELL__ >= 707
--- Data.Typeable is redundant
-#else
-import Data.Typeable
+
+#ifdef MIN_VERSION_containers
+import Data.Tree
 #endif
 
-infixl 4 <@, @>, <@@>, <@>, $>
+infixl 4 <@, @>, <@@>, <@>
 infixl 1 =>>
 infixr 1 <<=, =<=, =>=
 
@@ -76,9 +69,11 @@
 I. Provide definitions for 'extract' and 'extend'
 satisfying these laws:
 
-> extend extract      = id
-> extract . extend f  = f
-> extend f . extend g = extend (f . extend g)
+@
+'extend' 'extract'      = 'id'
+'extract' . 'extend' f  = f
+'extend' f . 'extend' g = 'extend' (f . 'extend' g)
+@
 
 In this case, you may simply set 'fmap' = 'liftW'.
 
@@ -87,16 +82,20 @@
 that Cokleisli composition must be associative, and has extract for
 a unit:
 
-> f =>= extract   = f
-> extract =>= f   = f
-> (f =>= g) =>= h = f =>= (g =>= h)
+@
+f '=>=' 'extract'   = f
+'extract' '=>=' f   = f
+(f '=>=' g) '=>=' h = f '=>=' (g '=>=' h)
+@
 
 II. Alternately, you may choose to provide definitions for 'fmap',
 'extract', and 'duplicate' satisfying these laws:
 
-> extract . duplicate      = id
-> fmap extract . duplicate = id
-> duplicate . duplicate    = fmap duplicate . duplicate
+@
+'extract' . 'duplicate'      = 'id'
+'fmap' 'extract' . 'duplicate' = 'id'
+'duplicate' . 'duplicate'    = 'fmap' 'duplicate' . 'duplicate'
+@
 
 In this case you may not rely on the ability to define 'fmap' in
 terms of 'liftW'.
@@ -104,9 +103,11 @@
 You may of course, choose to define both 'duplicate' /and/ 'extend'.
 In that case you must also satisfy these laws:
 
-> extend f  = fmap f . duplicate
-> duplicate = extend id
-> fmap f    = extend (f . extract)
+@
+'extend' f  = 'fmap' f . 'duplicate'
+'duplicate' = 'extend' id
+'fmap' f    = 'extend' (f . 'extract')
+@
 
 These are the default definitions of 'extend' and 'duplicate' and
 the definition of 'liftW' respectively.
@@ -115,27 +116,43 @@
 
 class Functor w => Comonad w where
   -- |
-  -- > extract . fmap f = f . extract
+  -- @
+  -- 'extract' . 'fmap' f = f . 'extract'
+  -- @
   extract :: w a -> a
 
   -- |
-  -- > duplicate = extend id
-  -- > fmap (fmap f) . duplicate = duplicate . fmap f
+  -- @
+  -- 'duplicate' = 'extend' 'id'
+  -- 'fmap' ('fmap' f) . 'duplicate' = 'duplicate' . 'fmap' f
+  -- @
   duplicate :: w a -> w (w a)
   duplicate = extend id
 
   -- |
-  -- > extend f = fmap f . duplicate
+  -- @
+  -- 'extend' f = 'fmap' f . 'duplicate'
+  -- @
   extend :: (w a -> b) -> w a -> w b
   extend f = fmap f . duplicate
 
+  {-# MINIMAL extract, (duplicate | extend) #-}
 
+
 instance Comonad ((,)e) where
   duplicate p = (fst p, p)
   {-# INLINE duplicate #-}
   extract = snd
   {-# INLINE extract #-}
 
+instance Comonad (Arg e) where
+  duplicate w@(Arg a _) = Arg a w
+  {-# INLINE duplicate #-}
+  extend f w@(Arg a _) = Arg a (f w)
+  {-# INLINE extend #-}
+  extract (Arg _ b) = b
+  {-# INLINE extract #-}
+
 instance Monoid m => Comonad ((->)m) where
   duplicate f m = f . mappend m
   {-# INLINE duplicate #-}
@@ -148,6 +165,13 @@
   extract = runIdentity
   {-# INLINE extract #-}
 
+-- $
+-- The variable `s` can have any kind.
+-- For example, here it has kind `Bool`:
+-- >>> :set -XDataKinds
+-- >>> import Data.Tagged
+-- >>> extract (Tagged 42 :: Tagged 'True Integer)
+-- 42
 instance Comonad (Tagged s) where
   duplicate = Tagged
   {-# INLINE duplicate #-}
@@ -159,43 +183,67 @@
   extract = extract . runIdentityT
   {-# INLINE extract #-}
 
+#ifdef MIN_VERSION_containers
 instance Comonad Tree where
   duplicate w@(Node _ as) = Node w (map duplicate as)
   extract (Node a _) = a
   {-# INLINE extract #-}
+#endif
 
 instance Comonad NonEmpty where
-  extend f w@ ~(_ :| aas) = f w :| case aas of
+  extend f w@(~(_ :| aas)) =
+    f w :| case aas of
       []     -> []
       (a:as) -> toList (extend f (a :| as))
   extract ~(a :| _) = a
   {-# INLINE extract #-}
 
+coproduct :: (f a -> b) -> (g a -> b) -> FSum.Sum f g a -> b
+coproduct f _ (FSum.InL x) = f x
+coproduct _ g (FSum.InR y) = g y
+{-# INLINE coproduct #-}
+
+instance (Comonad f, Comonad g) => Comonad (FSum.Sum f g) where
+  extend f = coproduct
+               (FSum.InL . extend (f . FSum.InL))
+               (FSum.InR . extend (f . FSum.InR))
+  extract = coproduct extract extract
+  {-# INLINE extract #-}
+
+
 -- | @ComonadApply@ is to @Comonad@ like @Applicative@ is to @Monad@.
 --
 -- Mathematically, it is a strong lax symmetric semi-monoidal comonad on the
 -- category @Hask@ of Haskell types. That it to say that @w@ is a strong lax
--- symmetric semi-monoidal functor on Hask, where both extract and duplicate are
+-- symmetric semi-monoidal functor on Hask, where both 'extract' and 'duplicate' are
 -- symmetric monoidal natural transformations.
 --
 -- Laws:
 --
--- > (.) <$> u <@> v <@> w = u <@> (v <@> w)
--- > extract (p <@> q) = extract p (extract q)
--- > duplicate (p <@> q) = (<@>) <$> duplicate p <@> duplicate q
+-- @
+-- ('.') '<$>' u '<@>' v '<@>' w = u '<@>' (v '<@>' w)
+-- 'extract' (p '<@>' q) = 'extract' p ('extract' q)
+-- 'duplicate' (p '<@>' q) = ('<@>') '<$>' 'duplicate' p '<@>' 'duplicate' q
+-- @
 --
--- If our type is both a ComonadApply and Applicative we further require
+-- If our type is both a 'ComonadApply' and 'Applicative' we further require
 --
--- > (<*>) = (<@>)
+-- @
+-- ('<*>') = ('<@>')
+-- @
 --
 -- Finally, if you choose to define ('<@') and ('@>'), the results of your
 -- definitions should match the following laws:
 --
--- > a @> b = const id <$> a <@> b
--- > a <@ b = const <$> a <@> b
+-- @
+-- a '@>' b = 'const' 'id' '<$>' a '<@>' b
+-- a '<@' b = 'const' '<$>' a '<@>' b
+-- @
 
 class Comonad w => ComonadApply w where
   (<@>) :: w (a -> b) -> w a -> w b
+  default (<@>) :: Applicative w => w (a -> b) -> w a -> w b
+  (<@>) = (<*>)
 
   (@>) :: w a -> w b -> w b
   a @> b = const id <$> a <@> b
@@ -224,28 +272,43 @@
 instance ComonadApply w => ComonadApply (IdentityT w) where
   IdentityT wa <@> IdentityT wb = IdentityT (wa <@> wb)
 
+#ifdef MIN_VERSION_containers
 instance ComonadApply Tree where
   (<@>) = (<*>)
   (<@ ) = (<* )
   ( @>) = ( *>)
+#endif
 
 -- | A suitable default definition for 'fmap' for a 'Comonad'.
 -- Promotes a function to a comonad.
 --
--- > fmap f = liftW f = extend (f . extract)
+-- You can only safely use 'liftW' to define 'fmap' if your 'Comonad'
+-- defines 'extend', not just 'duplicate', since defining
+-- 'extend' in terms of duplicate uses 'fmap'!
+--
+-- @
+-- 'fmap' f = 'liftW' f = 'extend' (f . 'extract')
+-- @
 liftW :: Comonad w => (a -> b) -> w a -> w b
 liftW f = extend (f . extract)
 {-# INLINE liftW #-}
 
--- | Comonadic fixed point à la Menendez
+-- | Comonadic fixed point à la David Menendez
 wfix :: Comonad w => w (w a -> a) -> a
 wfix w = extract w (extend wfix w)
 
--- | Comonadic fixed point à la Orchard
+-- | Comonadic fixed point à la Dominic Orchard
 cfix :: Comonad w => (w a -> a) -> w a
 cfix f = fix (extend f)
 {-# INLINE cfix #-}
 
+-- | Comonadic fixed point à la Kenneth Foner:
+--
+-- This is the @evaluate@ function from his <https://www.youtube.com/watch?v=F7F-BzOB670 "Getting a Quick Fix on Comonads"> talk.
+kfix :: ComonadApply w => w (w a -> a) -> w a
+kfix w = fix $ \u -> w <@> duplicate u
+{-# INLINE kfix #-}
+
 -- | 'extend' with the arguments swapped. Dual to '>>=' for a 'Monad'.
 (=>>) :: Comonad w => w a -> (w a -> b) -> w b
 (=>>) = flip extend
@@ -256,12 +319,12 @@
 (<<=) = extend
 {-# INLINE (<<=) #-}
 
--- | Right-to-left Cokleisli composition
+-- | Right-to-left 'Cokleisli' composition
 (=<=) :: Comonad w => (w b -> c) -> (w a -> b) -> w a -> c
 f =<= g = f . extend g
 {-# INLINE (=<=) #-}
 
--- | Left-to-right Cokleisli composition
+-- | Left-to-right 'Cokleisli' composition
 (=>=) :: Comonad w => (w a -> b) -> (w b -> c) -> w a -> c
 f =>= g = g . extend f
 {-# INLINE (=>=) #-}
@@ -271,12 +334,12 @@
 (<@@>) = liftW2 (flip id)
 {-# INLINE (<@@>) #-}
 
--- | Lift a binary function into a comonad with zipping
+-- | Lift a binary function into a 'Comonad' with zipping
 liftW2 :: ComonadApply w => (a -> b -> c) -> w a -> w b -> w c
 liftW2 f a b = f <$> a <@> b
 {-# INLINE liftW2 #-}
 
--- | Lift a ternary function into a comonad with zipping
+-- | Lift a ternary function into a 'Comonad' with zipping
 liftW3 :: ComonadApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
 liftW3 f a b c = f <$> a <@> b <@> c
 {-# INLINE liftW3 #-}
@@ -284,25 +347,6 @@
 -- | The 'Cokleisli' 'Arrow's of a given 'Comonad'
 newtype Cokleisli w a b = Cokleisli { runCokleisli :: w a -> b }
 
-#if __GLASGOW_HASKELL__ >= 707
--- instance Typeable (Cokleisli w) derived automatically
-#else
-#ifdef __GLASGOW_HASKELL__
-instance Typeable1 w => Typeable2 (Cokleisli w) where
-  typeOf2 twab = mkTyConApp cokleisliTyCon [typeOf1 (wa twab)]
-        where wa :: Cokleisli w a b -> w a
-              wa = undefined
-#endif
-
-cokleisliTyCon :: TyCon
-#if MIN_VERSION_base(4,4,0)
-cokleisliTyCon = mkTyCon3 "comonad" "Control.Comonad" "Cokleisli"
-#else
-cokleisliTyCon = mkTyCon "Control.Comonad.Cokleisli"
-#endif
-{-# NOINLINE cokleisliTyCon #-}
-#endif
-
 instance Comonad w => Category (Cokleisli w) where
   id = Cokleisli extract
   Cokleisli f . Cokleisli g = Cokleisli (f =<= g)
@@ -332,9 +376,5 @@
   Cokleisli f <*> Cokleisli a = Cokleisli (\w -> f w (a w))
 
 instance Monad (Cokleisli w a) where
-  return = Cokleisli . const
+  return = pure
   Cokleisli k >>= f = Cokleisli $ \w -> runCokleisli (f (k w)) w
-
--- | Replace the contents of a functor uniformly with a constant value.
-($>) :: Functor f => f a -> b -> f b
-($>) = flip (<$)
diff --git a/src/Control/Comonad/Env.hs b/src/Control/Comonad/Env.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Env.hs
@@ -0,0 +1,39 @@
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Env
+-- Copyright   :  (C) 2008-2014 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable (fundeps, MPTCs)
+--
+-- The Env comonad (aka the Coreader, Environment, or Product comonad)
+--
+-- A co-Kleisli arrow in the Env comonad is isomorphic to a Kleisli arrow
+-- in the reader monad.
+--
+-- (a -> e -> m) ~ (a, e) -> m ~ Env e a -> m
+----------------------------------------------------------------------------
+module Control.Comonad.Env (
+  -- * ComonadEnv class
+    ComonadEnv(..)
+  , asks
+  , local
+  -- * The Env comonad
+  , Env
+  , env
+  , runEnv
+  -- * The EnvT comonad transformer
+  , EnvT(..)
+  , runEnvT
+  -- * Re-exported modules
+  , module Control.Comonad
+  , module Control.Comonad.Trans.Class
+  ) where
+
+import Control.Comonad
+import Control.Comonad.Env.Class (ComonadEnv(..), asks)
+import Control.Comonad.Trans.Class
+import Control.Comonad.Trans.Env (Env, env, runEnv, EnvT(..), runEnvT, local)
diff --git a/src/Control/Comonad/Env/Class.hs b/src/Control/Comonad/Env/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Env/Class.hs
@@ -0,0 +1,56 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Env.Class
+-- Copyright   :  (C) 2008-2015 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable (fundeps, MPTCs)
+----------------------------------------------------------------------------
+module Control.Comonad.Env.Class
+  ( ComonadEnv(..)
+  , asks
+  ) where
+
+import Control.Comonad
+import Control.Comonad.Trans.Class
+import qualified Control.Comonad.Trans.Env as Env
+import Control.Comonad.Trans.Store
+import Control.Comonad.Trans.Traced
+import Control.Comonad.Trans.Identity
+import Data.Semigroup
+
+class Comonad w => ComonadEnv e w | w -> e where
+  ask :: w a -> e
+
+asks :: ComonadEnv e w => (e -> e') -> w a -> e'
+asks f wa = f (ask wa)
+{-# INLINE asks #-}
+
+instance Comonad w => ComonadEnv e (Env.EnvT e w) where
+  ask = Env.ask
+
+instance ComonadEnv e ((,)e) where
+  ask = fst
+
+instance ComonadEnv e (Arg e) where
+  ask (Arg e _) = e
+
+lowerAsk :: (ComonadEnv e w, ComonadTrans t) => t w a -> e
+lowerAsk = ask . lower
+{-# INLINE lowerAsk #-}
+
+instance ComonadEnv e w => ComonadEnv e (StoreT t w) where
+  ask = lowerAsk
+
+instance ComonadEnv e w => ComonadEnv e (IdentityT w) where
+  ask = lowerAsk
+
+instance (ComonadEnv e w, Monoid m) => ComonadEnv e (TracedT m w) where
+  ask = lowerAsk
diff --git a/src/Control/Comonad/Hoist/Class.hs b/src/Control/Comonad/Hoist/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Hoist/Class.hs
@@ -0,0 +1,27 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Hoist.Class
+-- Copyright   :  (C) 2008-2013 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  provisional
+-- Portability :  portable
+----------------------------------------------------------------------------
+module Control.Comonad.Hoist.Class
+  ( ComonadHoist(cohoist)
+  ) where
+
+import Control.Comonad
+import Control.Monad.Trans.Identity
+
+class ComonadHoist t where
+  -- | Given any comonad-homomorphism from @w@ to @v@ this yields a comonad
+  -- homomorphism from @t w@ to @t v@.
+  cohoist :: (Comonad w, Comonad v) => (forall x. w x -> v x) -> t w a -> t v a
+
+instance ComonadHoist IdentityT where
+  cohoist l = IdentityT . l . runIdentityT
+  {-# INLINE cohoist #-}
diff --git a/src/Control/Comonad/Identity.hs b/src/Control/Comonad/Identity.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Identity.hs
@@ -0,0 +1,20 @@
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Identity
+-- Copyright   :  (C) 2008-2014 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable (fundeps, MPTCs)
+----------------------------------------------------------------------------
+module Control.Comonad.Identity (
+    module Control.Comonad
+  , module Data.Functor.Identity
+  , module Control.Comonad.Trans.Identity
+  ) where
+
+import Control.Comonad
+import Data.Functor.Identity
+import Control.Comonad.Trans.Identity
diff --git a/src/Control/Comonad/Store.hs b/src/Control/Comonad/Store.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Store.hs
@@ -0,0 +1,30 @@
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Store
+-- Copyright   :  (C) 2008-2014 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable (fundeps, MPTCs)
+----------------------------------------------------------------------------
+module Control.Comonad.Store (
+  -- * ComonadStore class
+    ComonadStore(..)
+  -- * The Store comonad
+  , Store
+  , store
+  , runStore
+  -- * The StoreT comonad transformer
+  , StoreT(..)
+  , runStoreT
+  -- * Re-exported modules
+  , module Control.Comonad
+  , module Control.Comonad.Trans.Class
+  ) where
+
+import Control.Comonad
+import Control.Comonad.Store.Class (ComonadStore(..))
+import Control.Comonad.Trans.Class
+import Control.Comonad.Trans.Store (Store, store, runStore, StoreT(..), runStoreT)
diff --git a/src/Control/Comonad/Store/Class.hs b/src/Control/Comonad/Store/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Store/Class.hs
@@ -0,0 +1,78 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Store.Class
+-- Copyright   :  (C) 2008-2012 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable (fundeps, MPTCs)
+----------------------------------------------------------------------------
+module Control.Comonad.Store.Class
+  ( ComonadStore(..)
+  , lowerPos
+  , lowerPeek
+  ) where
+
+import Control.Comonad
+import Control.Comonad.Trans.Class
+import Control.Comonad.Trans.Env
+import qualified Control.Comonad.Trans.Store as Store
+import Control.Comonad.Trans.Traced
+import Control.Comonad.Trans.Identity
+
+class Comonad w => ComonadStore s w | w -> s where
+  pos :: w a -> s
+  peek :: s -> w a -> a
+
+  peeks :: (s -> s) -> w a -> a
+  peeks f w = peek (f (pos w)) w
+
+  seek :: s -> w a -> w a
+  seek s = peek s . duplicate
+
+  seeks :: (s -> s) -> w a -> w a
+  seeks f = peeks f . duplicate
+
+  experiment :: Functor f => (s -> f s) -> w a -> f a
+  experiment f w = fmap (`peek` w) (f (pos w))
+
+instance Comonad w => ComonadStore s (Store.StoreT s w) where
+  pos = Store.pos
+  peek = Store.peek
+  peeks = Store.peeks
+  seek = Store.seek
+  seeks = Store.seeks
+  experiment = Store.experiment
+
+lowerPos :: (ComonadTrans t, ComonadStore s w) => t w a -> s
+lowerPos = pos . lower
+{-# INLINE lowerPos #-}
+
+lowerPeek :: (ComonadTrans t, ComonadStore s w) => s -> t w a -> a
+lowerPeek s = peek s . lower
+{-# INLINE lowerPeek #-}
+
+lowerExperiment :: (ComonadTrans t, ComonadStore s w, Functor f) => (s -> f s) -> t w a -> f a
+lowerExperiment f = experiment f . lower
+{-# INLINE lowerExperiment #-}
+
+instance ComonadStore s w => ComonadStore s (IdentityT w) where
+  pos = lowerPos
+  peek = lowerPeek
+  experiment = lowerExperiment
+
+instance ComonadStore s w => ComonadStore s (EnvT e w) where
+  pos = lowerPos
+  peek = lowerPeek
+  experiment = lowerExperiment
+
+instance (ComonadStore s w, Monoid m) => ComonadStore s (TracedT m w) where
+  pos = lowerPos
+  peek = lowerPeek
+  experiment = lowerExperiment
diff --git a/src/Control/Comonad/Traced.hs b/src/Control/Comonad/Traced.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Traced.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Traced
+-- Copyright   :  (C) 2008-2014 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable (fundeps, MPTCs)
+----------------------------------------------------------------------------
+module Control.Comonad.Traced (
+  -- * ComonadTraced class
+    ComonadTraced(..)
+  , traces
+  -- * The Traced comonad
+  , Traced
+  , traced
+  , runTraced
+  -- * The TracedT comonad transformer
+  , TracedT(..)
+  -- * Re-exported modules
+  , module Control.Comonad
+  , module Control.Comonad.Trans.Class
+  , module Data.Monoid
+  ) where
+
+import Control.Comonad
+import Control.Comonad.Traced.Class (ComonadTraced(..), traces)
+import Control.Comonad.Trans.Class
+import Control.Comonad.Trans.Traced (Traced, traced, runTraced, TracedT(..), runTracedT)
+import Data.Monoid
diff --git a/src/Control/Comonad/Traced/Class.hs b/src/Control/Comonad/Traced/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Traced/Class.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Traced.Class
+-- Copyright   :  (C) 2008-2012 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  experimental
+-- Portability :  non-portable (fundeps, MPTCs)
+----------------------------------------------------------------------------
+module Control.Comonad.Traced.Class
+  ( ComonadTraced(..)
+  , traces
+  ) where
+
+import Control.Comonad
+import Control.Comonad.Trans.Class
+import Control.Comonad.Trans.Env
+import Control.Comonad.Trans.Store
+import qualified Control.Comonad.Trans.Traced as Traced
+import Control.Comonad.Trans.Identity
+
+class Comonad w => ComonadTraced m w | w -> m where
+  trace :: m -> w a -> a
+
+traces :: ComonadTraced m w => (a -> m) -> w a -> a
+traces f wa = trace (f (extract wa)) wa
+{-# INLINE traces #-}
+
+instance (Comonad w, Monoid m) => ComonadTraced m (Traced.TracedT m w) where
+  trace = Traced.trace
+
+instance Monoid m => ComonadTraced m ((->) m) where
+  trace m f = f m
+
+lowerTrace :: (ComonadTrans t, ComonadTraced m w) => m -> t w a -> a
+lowerTrace m = trace m . lower
+{-# INLINE lowerTrace #-}
+
+-- All of these require UndecidableInstances because they do not satisfy the coverage condition
+
+instance ComonadTraced m w => ComonadTraced m (IdentityT w) where
+  trace = lowerTrace
+
+instance ComonadTraced m w => ComonadTraced m (EnvT e w) where
+  trace = lowerTrace
+
+instance ComonadTraced m w => ComonadTraced m (StoreT s w) where
+  trace = lowerTrace
diff --git a/src/Control/Comonad/Trans/Class.hs b/src/Control/Comonad/Trans/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Trans/Class.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Trans.Class
+-- Copyright   :  (C) 2008-2015 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  provisional
+-- Portability :  portable
+----------------------------------------------------------------------------
+module Control.Comonad.Trans.Class
+  ( ComonadTrans(..) ) where
+
+import Control.Comonad
+import Control.Monad.Trans.Identity
+
+class ComonadTrans t where
+  lower :: Comonad w => t w a -> w a
+
+-- avoiding orphans
+instance ComonadTrans IdentityT where
+  lower = runIdentityT
diff --git a/src/Control/Comonad/Trans/Env.hs b/src/Control/Comonad/Trans/Env.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Trans/Env.hs
@@ -0,0 +1,153 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE Safe #-}
+{-# LANGUAGE StandaloneDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Trans.Env
+-- Copyright   :  (C) 2008-2013 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- The environment comonad holds a value along with some retrievable context.
+--
+-- This module specifies the environment comonad transformer (aka coreader),
+-- which is left adjoint to the reader comonad.
+--
+-- The following sets up an experiment that retains its initial value in the
+-- background:
+--
+-- >>> let initial = env 0 0
+--
+-- Extract simply retrieves the value:
+--
+-- >>> extract initial
+-- 0
+--
+-- Play around with the value, in our case producing a negative value:
+--
+-- >>> let experiment = fmap (+ 10) initial
+-- >>> extract experiment
+-- 10
+--
+-- Oh noes, something went wrong, 10 isn't very negative! Better restore the
+-- initial value using the default:
+--
+-- >>> let initialRestored = experiment =>> ask
+-- >>> extract initialRestored
+-- 0
+----------------------------------------------------------------------------
+module Control.Comonad.Trans.Env
+  (
+  -- * The strict environment comonad
+    Env
+  , env
+  , runEnv
+  -- * The strict environment comonad transformer
+  , EnvT(..)
+  , runEnvT
+  , lowerEnvT
+  -- * Combinators
+  , ask
+  , asks
+  , local
+  ) where
+
+import Control.Comonad
+import Control.Comonad.Hoist.Class
+import Control.Comonad.Trans.Class
+import Data.Data
+import Data.Functor.Identity
+#if !(MIN_VERSION_base(4,11,0))
+import Data.Semigroup
+#endif
+
+#ifdef __MHS__
+import Data.Foldable
+import Data.Traversable
+#endif
+
+-- $setup
+-- >>> import Control.Comonad
+
+instance
+  ( Data e
+  , Typeable w, Data (w a)
+  , Data a
+  ) => Data (EnvT e w a) where
+    gfoldl f z (EnvT e wa) = z EnvT `f` e `f` wa
+    toConstr _ = envTConstr
+    gunfold k z c = case constrIndex c of
+        1 -> k (k (z EnvT))
+        _ -> error "gunfold"
+    dataTypeOf _ = envTDataType
+    dataCast1 f = gcast1 f
+
+envTConstr :: Constr
+envTConstr = mkConstr envTDataType "EnvT" [] Prefix
+{-# NOINLINE envTConstr #-}
+
+envTDataType :: DataType
+envTDataType = mkDataType "Control.Comonad.Trans.Env.EnvT" [envTConstr]
+{-# NOINLINE envTDataType #-}
+
+type Env e = EnvT e Identity
+data EnvT e w a = EnvT e (w a)
+
+-- | Create an Env using an environment and a value
+env :: e -> a -> Env e a
+env e a = EnvT e (Identity a)
+
+runEnv :: Env e a -> (e, a)
+runEnv (EnvT e (Identity a)) = (e, a)
+
+runEnvT :: EnvT e w a -> (e, w a)
+runEnvT (EnvT e wa) = (e, wa)
+
+instance Functor w => Functor (EnvT e w) where
+  fmap g (EnvT e wa) = EnvT e (fmap g wa)
+
+instance Comonad w => Comonad (EnvT e w) where
+  duplicate (EnvT e wa) = EnvT e (extend (EnvT e) wa)
+  extract (EnvT _ wa) = extract wa
+
+instance ComonadTrans (EnvT e) where
+  lower (EnvT _ wa) = wa
+
+instance (Monoid e, Applicative m) => Applicative (EnvT e m) where
+  pure = EnvT mempty . pure
+  EnvT ef wf <*> EnvT ea wa = EnvT (ef `mappend` ea) (wf <*> wa)
+
+-- | Gets rid of the environment. This differs from 'extract' in that it will
+--   not continue extracting the value from the contained comonad.
+lowerEnvT :: EnvT e w a -> w a
+lowerEnvT (EnvT _ wa) = wa
+
+instance ComonadHoist (EnvT e) where
+  cohoist l (EnvT e wa) = EnvT e (l wa)
+
+instance (Semigroup e, ComonadApply w) => ComonadApply (EnvT e w) where
+  EnvT ef wf <@> EnvT ea wa = EnvT (ef <> ea) (wf <@> wa)
+
+instance Foldable w => Foldable (EnvT e w) where
+  foldMap f (EnvT _ w) = foldMap f w
+
+instance Traversable w => Traversable (EnvT e w) where
+  traverse f (EnvT e w) = EnvT e <$> traverse f w
+
+-- | Retrieves the environment.
+ask :: EnvT e w a -> e
+ask (EnvT e _) = e
+
+-- | Like 'ask', but modifies the resulting value with a function.
+--
+--   > asks = f . ask
+asks :: (e -> f) -> EnvT e w a -> f
+asks f (EnvT e _) = f e
+
+-- | Modifies the environment using the specified function.
+local :: (e -> e') -> EnvT e w a -> EnvT e' w a
+local f (EnvT e wa) = EnvT (f e) wa
diff --git a/src/Control/Comonad/Trans/Identity.hs b/src/Control/Comonad/Trans/Identity.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Trans/Identity.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Trans.Identity
+-- Copyright   :  (C) 2008-2011 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+----------------------------------------------------------------------------
+module Control.Comonad.Trans.Identity
+  ( IdentityT(..)
+  ) where
+
+import Control.Monad.Trans.Identity
diff --git a/src/Control/Comonad/Trans/Store.hs b/src/Control/Comonad/Trans/Store.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Trans/Store.hs
@@ -0,0 +1,175 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE Safe #-}
+{-# LANGUAGE StandaloneDeriving #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Trans.Store
+-- Copyright   :  (C) 2008-2013 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+--
+-- The store comonad holds a constant value along with a modifiable /accessor/
+-- function, which maps the /stored value/ to the /focus/.
+--
+-- This module defines the strict store (aka state-in-context/costate) comonad
+-- transformer.
+--
+-- @stored value = (1, 5)@, @accessor = fst@, @resulting focus = 1@:
+--
+-- >>> :{
+--  let
+--    storeTuple :: Store (Int, Int) Int
+--    storeTuple = store fst (1, 5)
+-- :}
+--
+-- Add something to the focus:
+--
+-- >>> :{
+--  let
+--    addToFocus :: Int -> Store (Int, Int) Int -> Int
+--    addToFocus x wa = x + extract wa
+-- :}
+--
+-- >>> :{
+--   let
+--     added3 :: Store (Int, Int) Int
+--     added3 = extend (addToFocus 3) storeTuple
+-- :}
+--
+-- The focus of added3 is now @1 + 3 = 4@. However, this action changed only
+-- the accessor function and therefore the focus but not the stored value:
+--
+-- >>> pos added3
+-- (1,5)
+--
+-- >>> extract added3
+-- 4
+--
+-- The strict store (state-in-context/costate) comonad transformer is subject
+-- to the laws:
+--
+-- > x = seek (pos x) x
+-- > y = pos (seek y x)
+-- > seek y x = seek y (seek z x)
+--
+-- Thanks go to Russell O'Connor and Daniel Peebles for their help formulating
+-- and proving the laws for this comonad transformer.
+----------------------------------------------------------------------------
+module Control.Comonad.Trans.Store
+  (
+  -- * The Store comonad
+    Store, store, runStore
+  -- * The Store comonad transformer
+  , StoreT(..), runStoreT
+  -- * Operations
+  , pos
+  , seek, seeks
+  , peek, peeks
+  , experiment
+  ) where
+
+import Control.Comonad
+import Control.Comonad.Hoist.Class
+import Control.Comonad.Trans.Class
+import Data.Functor.Identity
+#if !(MIN_VERSION_base(4,11,0))
+import Data.Semigroup
+#endif
+
+-- $setup
+-- >>> import Control.Comonad
+-- >>> import Data.Tuple (swap)
+
+type Store s = StoreT s Identity
+
+-- | Create a Store using an accessor function and a stored value
+store :: (s -> a) -> s -> Store s a
+store f s = StoreT (Identity f) s
+
+runStore :: Store s a -> (s -> a, s)
+runStore (StoreT (Identity f) s) = (f, s)
+
+data StoreT s w a = StoreT (w (s -> a)) s
+
+runStoreT :: StoreT s w a -> (w (s -> a), s)
+runStoreT (StoreT wf s) = (wf, s)
+
+instance Functor w => Functor (StoreT s w) where
+  fmap f (StoreT wf s) = StoreT (fmap (f .) wf) s
+
+instance (ComonadApply w, Semigroup s) => ComonadApply (StoreT s w) where
+  StoreT ff m <@> StoreT fa n = StoreT ((<*>) <$> ff <@> fa) (m <> n)
+
+instance (Applicative w, Monoid s) => Applicative (StoreT s w) where
+  pure a = StoreT (pure (const a)) mempty
+  StoreT ff m <*> StoreT fa n = StoreT ((<*>) <$> ff <*> fa) (mappend m n)
+
+instance Comonad w => Comonad (StoreT s w) where
+  duplicate (StoreT wf s) = StoreT (extend StoreT wf) s
+  extend f (StoreT wf s) = StoreT (extend (\wf' s' -> f (StoreT wf' s')) wf) s
+  extract (StoreT wf s) = extract wf s
+
+instance ComonadTrans (StoreT s) where
+  lower (StoreT f s) = fmap ($ s) f
+
+instance ComonadHoist (StoreT s) where
+  cohoist l (StoreT f s) = StoreT (l f) s
+
+-- | Read the stored value
+--
+-- >>> pos $ store fst (1,5)
+-- (1,5)
+--
+pos :: StoreT s w a -> s
+pos (StoreT _ s) = s
+
+-- | Set the stored value
+--
+-- >>> pos . seek (3,7) $ store fst (1,5)
+-- (3,7)
+--
+-- Seek satisfies the law
+--
+-- > seek s = peek s . duplicate
+seek :: s -> StoreT s w a -> StoreT s w a
+seek s ~(StoreT f _) = StoreT f s
+
+-- | Modify the stored value
+--
+-- >>> pos . seeks swap $ store fst (1,5)
+-- (5,1)
+--
+-- Seeks satisfies the law
+--
+-- > seeks f = peeks f . duplicate
+seeks :: (s -> s) -> StoreT s w a -> StoreT s w a
+seeks f ~(StoreT g s) = StoreT g (f s)
+
+-- | Peek at what the current focus would be for a different stored value
+--
+-- Peek satisfies the law
+--
+-- > peek x . extend (peek y) = peek y
+peek :: Comonad w => s -> StoreT s w a -> a
+peek s (StoreT g _) = extract g s
+
+
+-- | Peek at what the current focus would be if the stored value was
+--   modified by some function
+peeks :: Comonad w => (s -> s) -> StoreT s w a -> a
+peeks f ~(StoreT g s) = extract g (f s)
+
+-- | Applies a functor-valued function to the stored value, and then uses the
+--   new accessor to read the resulting focus.
+--
+--   >>> let f x = if x > 0 then Just (x^2) else Nothing
+--   >>> experiment f $ store (+1) 2
+--   Just 5
+--   >>> experiment f $ store (+1) (-2)
+--   Nothing
+experiment :: (Comonad w, Functor f) => (s -> f s) -> StoreT s w a -> f a
+experiment f (StoreT wf s) = extract wf <$> f s
diff --git a/src/Control/Comonad/Trans/Traced.hs b/src/Control/Comonad/Trans/Traced.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Comonad/Trans/Traced.hs
@@ -0,0 +1,106 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE Safe #-}
+{-# LANGUAGE StandaloneDeriving #-}
+#ifdef MIN_VERSION_indexed_traversable
+{-# LANGUAGE MultiParamTypeClasses, UndecidableInstances #-}
+#endif
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Comonad.Trans.Traced
+-- Copyright   :  (C) 2008-2014 Edward Kmett
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
+-- Stability   :  provisional
+-- Portability :  portable
+--
+-- The trace comonad builds up a result by prepending monoidal values to each
+-- other.
+--
+-- This module specifies the traced comonad transformer (aka the cowriter or
+-- exponential comonad transformer).
+--
+----------------------------------------------------------------------------
+module Control.Comonad.Trans.Traced
+  (
+  -- * Traced comonad
+    Traced
+  , traced
+  , runTraced
+  -- * Traced comonad transformer
+  , TracedT(..)
+  -- * Operations
+  , trace
+  , listen
+  , listens
+  , censor
+  ) where
+
+import Control.Monad (ap)
+import Control.Comonad
+import Control.Comonad.Hoist.Class
+import Control.Comonad.Trans.Class
+
+#ifdef MIN_VERSION_distributive
+import Data.Distributive
+#endif
+
+#ifdef MIN_VERSION_indexed_traversable
+import Data.Functor.WithIndex
+#endif
+
+import Data.Functor.Identity
+
+
+type Traced m = TracedT m Identity
+
+traced :: (m -> a) -> Traced m a
+traced f = TracedT (Identity f)
+
+runTraced :: Traced m a -> m -> a
+runTraced (TracedT (Identity f)) = f
+
+newtype TracedT m w a = TracedT { runTracedT :: w (m -> a) }
+
+instance Functor w => Functor (TracedT m w) where
+  fmap g = TracedT . fmap (g .) . runTracedT
+
+instance (ComonadApply w, Monoid m) => ComonadApply (TracedT m w) where
+  TracedT wf <@> TracedT wa = TracedT (ap <$> wf <@> wa)
+
+instance Applicative w => Applicative (TracedT m w) where
+  pure = TracedT . pure . const
+  TracedT wf <*> TracedT wa = TracedT (ap <$> wf <*> wa)
+
+instance (Comonad w, Monoid m) => Comonad (TracedT m w) where
+  extend f = TracedT . extend (\wf m -> f (TracedT (fmap (. mappend m) wf))) . runTracedT
+  extract (TracedT wf) = extract wf mempty
+
+instance Monoid m => ComonadTrans (TracedT m) where
+  lower = fmap ($ mempty) . runTracedT
+
+instance ComonadHoist (TracedT m) where
+  cohoist l = TracedT . l . runTracedT
+
+#ifdef MIN_VERSION_distributive
+instance Distributive w => Distributive (TracedT m w) where
+  distribute = TracedT . fmap (\tma m -> fmap ($ m) tma) . collect runTracedT
+#endif
+
+#ifdef MIN_VERSION_indexed_traversable
+instance FunctorWithIndex i w => FunctorWithIndex (s, i) (TracedT s w) where
+  imap f (TracedT w) = TracedT $ imap (\k' g k -> f (k, k') (g k)) w
+  {-# INLINE imap #-}
+#endif
+
+trace :: Comonad w => m -> TracedT m w a -> a
+trace m (TracedT wf) = extract wf m
+
+listen :: Functor w => TracedT m w a -> TracedT m w (a, m)
+listen = TracedT . fmap (\f m -> (f m, m)) . runTracedT
+
+listens :: Functor w => (m -> b) -> TracedT m w a -> TracedT m w (a, b)
+listens g = TracedT . fmap (\f m -> (f m, g m)) . runTracedT
+
+censor :: Functor w => (m -> m) -> TracedT m w a -> TracedT m w a
+censor g = TracedT . fmap (. g) . runTracedT
diff --git a/src/Data/Functor/Composition.hs b/src/Data/Functor/Composition.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Functor/Composition.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE Safe #-}
+module Data.Functor.Composition
+  ( Composition(..) ) where
+
+import Data.Functor.Compose
+
+-- | We often need to distinguish between various forms of Functor-like composition in Haskell in order to please the type system.
+-- This lets us work with these representations uniformly.
+class Composition o where
+  decompose :: o f g x -> f (g x)
+  compose :: f (g x) -> o f g x
+
+instance Composition Compose where
+  decompose = getCompose
+  compose = Compose
diff --git a/tests/doctests.hsc b/tests/doctests.hsc
deleted file mode 100644
--- a/tests/doctests.hsc
+++ /dev/null
@@ -1,74 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE ForeignFunctionInterface #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Main (doctests)
--- Copyright   :  (C) 2012-13 Edward Kmett
--- License     :  BSD-style (see the file LICENSE)
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  provisional
--- Portability :  portable
---
--- This module provides doctests for a project based on the actual versions
--- of the packages it was built with. It requires a corresponding Setup.lhs
--- to be added to the project
------------------------------------------------------------------------------
-module Main where
-
-import Build_doctests (deps)
-import Control.Applicative
-import Control.Monad
-import Data.List
-import System.Directory
-import System.FilePath
-import Test.DocTest
-
-##if defined(mingw32_HOST_OS)
-##if defined(i386_HOST_ARCH)
-##define USE_CP
-import Control.Applicative
-import Control.Exception
-import Foreign.C.Types
-foreign import stdcall "windows.h SetConsoleCP" c_SetConsoleCP :: CUInt -> IO Bool
-foreign import stdcall "windows.h GetConsoleCP" c_GetConsoleCP :: IO CUInt
-##elif defined(x86_64_HOST_ARCH)
-##define USE_CP
-import Control.Applicative
-import Control.Exception
-import Foreign.C.Types
-foreign import ccall "windows.h SetConsoleCP" c_SetConsoleCP :: CUInt -> IO Bool
-foreign import ccall "windows.h GetConsoleCP" c_GetConsoleCP :: IO CUInt
-##endif
-##endif
-
--- | Run in a modified codepage where we can print UTF-8 values on Windows.
-withUnicode :: IO a -> IO a
-##ifdef USE_CP
-withUnicode m = do
-  cp <- c_GetConsoleCP
-  (c_SetConsoleCP 65001 >> m) `finally` c_SetConsoleCP cp
-##else
-withUnicode m = m
-##endif
-
-main :: IO ()
-main = withUnicode $ getSources >>= \sources -> doctest $
-    "-isrc"
-  : "-idist/build/autogen"
-  : "-optP-include"
-  : "-optPdist/build/autogen/cabal_macros.h"
-  : "-hide-all-packages"
-  : "-Iincludes"
-  : map ("-package="++) deps ++ sources
-
-getSources :: IO [FilePath]
-getSources = filter (isSuffixOf ".hs") <$> go "src"
-  where
-    go dir = do
-      (dirs, files) <- getFilesAndDirectories dir
-      (files ++) . concat <$> mapM go dirs
-
-getFilesAndDirectories :: FilePath -> IO ([FilePath], [FilePath])
-getFilesAndDirectories dir = do
-  c <- map (dir </>) . filter (`notElem` ["..", "."]) <$> getDirectoryContents dir
-  (,) <$> filterM doesDirectoryExist c <*> filterM doesFileExist c
