diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,36 +1,58 @@
 # Changelog
+
 All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/).
 
+## 0.2.0.2 – 2023–12–21
+
+### Changed
+
+- updated formatting for newer Ormolu
+
 ## 0.2.0.1 – 2020–05–18
+
 ### Changed
+
 - Turned on StrictData
 
 ## 0.2.0.0 – 2020–05–14
+
 ### Changed
+
 - updated in sync with polykinding changes in yaya-0.3.0.0
 
 ## 0.1.1.3 – 2020–05–14
+
 ### Changed
+
 - enabled and fixed warnings
 
 ## 0.1.1.2 – 2019–11–08
+
 ### Changed
+
 - improved documentation
 
 ## 0.1.1.1 – 2019–11–08
+
 ### Added
+
 - tests for `law_cataCompose` (which bumps the yaya-hedgehog dependency for tests)
 
 ## 0.1.1.0 – 2019–01–08
+
 ### Added
+
 - lower bounds on internal yaya dependencies
 
 ### Changed
+
 - weakened constraints on a couple operations
 
 ## 0.1.0.0 – 2019–01–04
+
 ### Added
+
 - everything (this is the initial release)
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
 Unsafe extensions to the Yaya recursion scheme library.
 
 This includes
+
 - `Recursive` instances for lazily-recursive types
 - `Corecursive` instances for strictly-recursive types
 - operations on trees that can’t be implemented in a total fashion.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,17 @@
+-- __NB__: `custom-setup` doesn’t have any way to specify extensions, so any we
+--         want need to be specified here.
+{-# LANGUAGE PackageImports #-}
+{-# LANGUAGE Unsafe #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# OPTIONS_GHC -Weverything #-}
+-- Warns even when `Unsafe` is explicit, not inferred. See
+-- https://gitlab.haskell.org/ghc/ghc/-/issues/16689
+{-# OPTIONS_GHC -Wno-unsafe #-}
+
+module Main (main) where
+
+import safe "base" System.IO (IO)
+import "cabal-doctest" Distribution.Extra.Doctest (defaultMainWithDoctests)
+
+main :: IO ()
+main = defaultMainWithDoctests "doctests"
diff --git a/src/Yaya/Unsafe/Applied.hs b/src/Yaya/Unsafe/Applied.hs
new file mode 100644
--- /dev/null
+++ b/src/Yaya/Unsafe/Applied.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE Safe #-}
+
+module Yaya.Unsafe.Applied
+  ( unsafeFromList,
+  )
+where
+
+import "yaya" Yaya.Fold (Steppable (embed))
+import "yaya" Yaya.Pattern (XNor)
+import "this" Yaya.Unsafe.Fold (unsafeCata)
+
+-- | An unsafe implementation of `GHC.Exts.fromList` for `Steppable`
+--   fixed-points of `XNor`.
+unsafeFromList :: (Steppable (->) t (XNor a)) => [a] -> t
+unsafeFromList = unsafeCata embed
diff --git a/src/Yaya/Unsafe/Fold.hs b/src/Yaya/Unsafe/Fold.hs
--- a/src/Yaya/Unsafe/Fold.hs
+++ b/src/Yaya/Unsafe/Fold.hs
@@ -1,99 +1,184 @@
+{-# LANGUAGE Safe #-}
+
 -- | Definitions and instances that use direct recursion, which (because of
 --   laziness) can lead to non-termination.
-module Yaya.Unsafe.Fold where
+module Yaya.Unsafe.Fold
+  ( anaM,
+    corecursivePrism,
+    ganaM,
+    ghylo,
+    ghyloM,
+    hylo,
+    hyloM,
+    stream',
+    streamAna,
+    streamGApo,
+    unsafeAna,
+    unsafeCata,
+  )
+where
 
-import Control.Arrow
-import Control.Comonad
-import Control.Lens
-import Control.Monad
-import Data.Functor.Compose
+import "base" Control.Applicative (Applicative (pure))
+import "base" Control.Category (Category ((.)))
+import "base" Control.Monad (Monad, (<=<))
+import "base" Data.Bifunctor (Bifunctor (first))
+import "base" Data.Function (flip)
+import "base" Data.Functor (Functor (fmap))
+import "base" Data.Functor.Compose (Compose (Compose, getCompose))
+import "base" Data.Traversable (Traversable (sequenceA))
+import "comonad" Control.Comonad (Comonad (extract))
+import "lens" Control.Lens (Prism', matching, prism, review, (&))
+import "yaya" Yaya.Fold
+  ( Algebra,
+    AlgebraM,
+    Coalgebra,
+    CoalgebraM,
+    CoalgebraPrism,
+    Corecursive (ana),
+    DistributiveLaw,
+    GAlgebra,
+    GAlgebraM,
+    GCoalgebra,
+    GCoalgebraM,
+    Projectable (project),
+    Recursive (cata),
+    Steppable (embed),
+    lowerAlgebra,
+    lowerAlgebraM,
+    lowerCoalgebra,
+    lowerCoalgebraM,
+  )
+import "yaya" Yaya.Pattern (Maybe, Pair, maybe, uncurry)
 
-import Yaya.Fold
+-- | Instances leak transitively, so while "Yaya.Unsafe.Fold.Instances" exists,
+--   it should only be used when it is unavoidable. If you are explicitly
+--   folding a structure unsafely, use this function instead of importing that
+--   module.
+unsafeAna :: (Steppable (->) t f, Functor f) => Coalgebra (->) f a -> a -> t
+unsafeAna = hylo embed
 
--- | This can’t be implemented in a total fashion. There is a _similar_ approach
+-- | Instances leak transitively, so while "Yaya.Unsafe.Fold.Instances" exists,
+--   it should only be used when it is unavoidable. If you are explicitly
+--   unfolding a structure unsafely, use this function instead of importing that
+--   module.
+--
+--   Should one prefer `unsafeAna` or `unsafeCata` in cases where both are
+--   applicable?
+-- - one may provide weaker constraints than the other in certain cases (e.g.,
+--   on its own, `unsafeCata` only requires `Projectable` on the source, but
+--  `unsafeAna` requires `Steppable` on the target. Depending on what other
+--   constraints already exist on the function, either one may ultimately be
+--   less constrained.
+-- - they may fail differently: `unsafeCata` (folding a potentially-infinite
+--   structure) is likely to result in non-termination, whereas `unsafeAna`
+--   (building a potentially-infinite structure strictly) is likely to use up
+--   the memory or overflow the stack.
+unsafeCata :: (Projectable (->) t f, Functor f) => Algebra (->) f a -> t -> a
+unsafeCata = flip hylo project
+
+-- | This can’t be implemented in a total fashion. There is a /similar/ approach
 --   that can be total – with `ψ :: CoalgebraM (->) m f a`, `ana (Compose . ψ)`
 --   results in something like `Nu (Compose m f)` which is akin to an effectful
 --   stream.
-anaM :: (Monad m, Steppable (->) t f, Traversable f) => CoalgebraM (->) m f a -> a -> m t
+anaM ::
+  (Monad m, Steppable (->) t f, Traversable f) =>
+  CoalgebraM (->) m f a ->
+  a ->
+  m t
 anaM = hyloM (pure . embed)
 
-ganaM
-  :: (Monad m, Monad n, Traversable n, Steppable (->) t f, Traversable f)
-  => DistributiveLaw (->) n f
-  -> GCoalgebraM (->) m n f a
-  -> a -> m t
+ganaM ::
+  (Monad m, Monad n, Traversable n, Steppable (->) t f, Traversable f) =>
+  DistributiveLaw (->) n f ->
+  GCoalgebraM (->) m n f a ->
+  a ->
+  m t
 ganaM k ψ = anaM (lowerCoalgebraM k ψ) . pure
 
 -- | Fusion of an 'ana' and 'cata'.
-hylo :: Functor f => Algebra (->) f b -> Coalgebra (->) f a -> a -> b
+hylo :: (Functor f) => Algebra (->) f b -> Coalgebra (->) f a -> a -> b
 hylo φ ψ = go
   where
     go = φ . fmap go . ψ
 
-ghylo
-  :: (Comonad w, Monad m, Functor f)
-  => DistributiveLaw (->) f w
-  -> DistributiveLaw (->) m f
-  -> GAlgebra (->) w f b
-  -> GCoalgebra (->) m f a
-  -> a -> b
+ghylo ::
+  (Comonad w, Monad m, Functor f) =>
+  DistributiveLaw (->) f w ->
+  DistributiveLaw (->) m f ->
+  GAlgebra (->) w f b ->
+  GCoalgebra (->) m f a ->
+  a ->
+  b
 ghylo w m φ ψ =
   extract . hylo (lowerAlgebra w φ) (lowerCoalgebra m ψ) . pure
 
-hyloM
-  :: (Monad m, Traversable f)
-  => AlgebraM (->) m f b
-  -> CoalgebraM (->) m f a
-  -> a -> m b
+hyloM ::
+  (Monad m, Traversable f) =>
+  AlgebraM (->) m f b ->
+  CoalgebraM (->) m f a ->
+  a ->
+  m b
 hyloM φ ψ = hylo (φ <=< sequenceA <=< getCompose) (Compose . ψ)
 
-ghyloM
-  :: (Comonad w, Traversable w, Monad m, Traversable f, Monad n, Traversable n)
-  => DistributiveLaw (->) f w
-  -> DistributiveLaw (->) n f
-  -> GAlgebraM (->) m w f b
-  -> GCoalgebraM (->) m n f a
-  -> a -> m b
+ghyloM ::
+  (Comonad w, Traversable w, Monad m, Traversable f, Monad n, Traversable n) =>
+  DistributiveLaw (->) f w ->
+  DistributiveLaw (->) n f ->
+  GAlgebraM (->) m w f b ->
+  GCoalgebraM (->) m n f a ->
+  a ->
+  m b
 ghyloM w n φ ψ =
   fmap extract . hyloM (lowerAlgebraM w φ) (lowerCoalgebraM n ψ) . pure
 
-stream'
-  :: (Projectable (->) t f, Steppable (->) u g, Functor g)
-  => CoalgebraM (->) Maybe g b
-  -> (b -> ((b -> b, t) -> u) -> f t -> u)
-  -> b
-  -> t -> u
+stream' ::
+  (Projectable (->) t f, Steppable (->) u g, Functor g) =>
+  CoalgebraM (->) Maybe g b ->
+  (b -> (Pair (b -> b) t -> u) -> f t -> u) ->
+  b ->
+  t ->
+  u
 stream' ψ f = go
   where
     go c x =
-      maybe (f c (uncurry go . ((&) c *** id)) (project x))
-            (embed . fmap (flip go x))
-            (ψ c)
+      maybe
+        (f c (uncurry go . first (c &)) (project x))
+        (embed . fmap (`go` x))
+        (ψ c)
 
 -- | Gibbons’ metamorphism. It lazily folds a (necessarily infinite) value,
 --   incrementally re-expanding that value into some new representation.
-streamAna
-  :: (Projectable (->) t f, Steppable (->) u g, Functor g)
-  => CoalgebraM (->) Maybe g b
-  -> AlgebraM (->) ((,) (b -> b)) f t
-  -> b
-  -> t -> u
-streamAna ψ φ = stream' ψ (\_ f -> f . φ)
+--
+--  __NB__: See https://gist.github.com/sellout/4709e723cb649110af00217486c4466b
+--          for some commentary and explanation.
+streamAna ::
+  (Projectable (->) t f, Steppable (->) u g, Functor g) =>
+  CoalgebraM (->) Maybe g b ->
+  AlgebraM (->) (Pair (b -> b)) f t ->
+  b ->
+  t ->
+  u
+streamAna process accum = stream' process (\_ f -> f . accum)
 
 -- | Another form of Gibbons’ metamorphism. This one can be applied to non-
 --   infinite inputs and takes an additional “flushing” coalgebra to be applied
 --   after all the input has been consumed.
-streamGApo
-  :: (Projectable (->) t f, Steppable (->) u g, Corecursive (->) u g, Functor g)
-  => Coalgebra (->) g b
-  -> CoalgebraM (->) Maybe g b
-  -> (f t -> Maybe (b -> b, t))
-  -> b
-  -> t -> u
-streamGApo ψ' ψ φ = stream' ψ (\c f -> maybe (ana ψ' c) f . φ)
+--
+--  __NB__: See https://gist.github.com/sellout/4709e723cb649110af00217486c4466b
+--          for some commentary and explanation.
+streamGApo ::
+  (Projectable (->) t f, Steppable (->) u g, Corecursive (->) u g, Functor g) =>
+  Coalgebra (->) g b ->
+  CoalgebraM (->) Maybe g b ->
+  (f t -> Maybe (Pair (b -> b) t)) ->
+  b ->
+  t ->
+  u
+streamGApo flush process accum =
+  stream' process (\c f -> maybe (ana flush c) f . accum)
 
-corecursivePrism
-  :: (Steppable (->) t f, Recursive (->) t f, Corecursive (->) t f, Traversable f)
-  => CoalgebraPrism f a
-  -> Prism' a t
+corecursivePrism ::
+  (Steppable (->) t f, Recursive (->) t f, Traversable f) =>
+  CoalgebraPrism f a ->
+  Prism' a t
 corecursivePrism alg = prism (cata (review alg)) (anaM (matching alg))
diff --git a/src/Yaya/Unsafe/Fold/Instances.hs b/src/Yaya/Unsafe/Fold/Instances.hs
--- a/src/Yaya/Unsafe/Fold/Instances.hs
+++ b/src/Yaya/Unsafe/Fold/Instances.hs
@@ -1,41 +1,81 @@
-{-# options_ghc -Wno-orphans #-}
+{-# LANGUAGE CPP #-}
 
+-- __NB__: base-4.17 moves `IsList` to its own module, which avoids the unsafety
+--         of importing "GHC.Exts". With prior versions of base, we at least
+--         mark the module @Trustworthy@.
+#if MIN_VERSION_base(4, 17, 0)
+{-# LANGUAGE Safe #-}
+#else
+{-# LANGUAGE Trustworthy #-}
+#endif
+{-# LANGUAGE TypeFamilies #-}
+{-# OPTIONS_GHC -Wno-orphans #-}
+
 -- | Type class instances that use direct recursion in a potentially partial
 --   way. This is separated from the rest of `Yaya.Unsafe.Fold` because you can
 --   neither control nor qualify the import of instances. Therefore this module
---   is _extra_ dangerous, as having these instances available applies to the
+--   is /extra/ dangerous, as having these instances available applies to the
 --   entire module they’re imported into.
 --
---   This contains instances that you might _expect_ to see, but which aren’t
---   actually total. For example, folding a lazy list `[a]` is _not_ guaranteed
+--   This contains instances that you might /expect/ to see, but which aren’t
+--   actually total. For example, folding a lazy list @[a]@ is /not/ guaranteed
 --   to terminate.
-module Yaya.Unsafe.Fold.Instances where
+module Yaya.Unsafe.Fold.Instances
+  ( seqFreeT,
+  )
+where
 
-import           Control.Comonad.Cofree
-import           Control.Comonad.Env
-import           Control.Monad.Trans.Free
-import           Data.Functor.Classes
-import           Data.List.NonEmpty
+import safe "base" Control.Category (Category ((.)))
+import safe "base" Data.Eq (Eq ((==)))
+import safe "base" Data.Foldable (Foldable)
+import safe "base" Data.Function (flip)
+import safe "base" Data.Functor (Functor, (<$>))
+import safe "base" Data.Functor.Classes (Eq1, Show1)
+import safe "base" Data.List.NonEmpty (NonEmpty)
 
-import           Yaya.Fold
-import           Yaya.Fold.Native
-import           Yaya.Pattern
-import qualified Yaya.Unsafe.Fold as Unsafe
+-- See comment on @{-# LANGUAGE Safe #-}@ above.
+#if MIN_VERSION_base(4, 17, 0)
+import "base" GHC.IsList (IsList (Item, fromList, fromListN, toList))
+#else
+import "base" GHC.Exts (IsList (Item, fromList, fromListN, toList))
+#endif
+import safe "base" Text.Show (Show (showsPrec))
+import safe "comonad" Control.Comonad.Env (EnvT)
+import safe "free" Control.Comonad.Cofree (Cofree)
+import safe "free" Control.Monad.Trans.Free (Free, FreeF (Free, Pure), free)
+import safe "yaya" Yaya.Fold
+  ( Corecursive (ana),
+    DistributiveLaw,
+    Mu,
+    Nu,
+    Projectable (project),
+    Recursive (cata),
+    Steppable (embed),
+    recursiveEq,
+    recursiveShowsPrec,
+  )
+import safe "yaya" Yaya.Fold.Native (Cofix, Fix)
+import safe "yaya" Yaya.Pattern (AndMaybe, XNor)
+import safe "this" Yaya.Unsafe.Applied (unsafeFromList)
+import safe qualified "this" Yaya.Unsafe.Fold as Unsafe
 
-instance Functor f => Recursive (->) (Fix f) f where
+instance (Functor f) => Corecursive (->) (Fix f) f where
+  ana = Unsafe.hylo embed
+
+instance (Functor f) => Recursive (->) (Cofix f) f where
   cata = flip Unsafe.hylo project
 
-instance (Functor f, Foldable f, Eq1 f) => Eq (Fix f) where
+instance (Functor f, Foldable f, Eq1 f) => Eq (Cofix f) where
   (==) = recursiveEq
 
-instance (Functor f, Show1 f) => Show (Fix f) where
+instance (Functor f, Show1 f) => Show (Cofix f) where
   showsPrec = recursiveShowsPrec
 
-instance Functor f => Corecursive (->) (Mu f) f where
-  ana = Unsafe.hylo embed
+instance (Functor f) => Corecursive (->) (Mu f) f where
+  ana = Unsafe.unsafeAna
 
-instance Functor f => Recursive (->) (Nu f) f where
-  cata = flip Unsafe.hylo project
+instance (Functor f) => Recursive (->) (Nu f) f where
+  cata = Unsafe.unsafeCata
 
 instance (Functor f, Foldable f, Eq1 f) => Eq (Nu f) where
   (==) = recursiveEq
@@ -44,25 +84,48 @@
   showsPrec = recursiveShowsPrec
 
 instance Recursive (->) [a] (XNor a) where
-  cata = flip Unsafe.hylo project
+  cata = Unsafe.unsafeCata
 
 instance Recursive (->) (NonEmpty a) (AndMaybe a) where
-  cata = flip Unsafe.hylo project
+  cata = Unsafe.unsafeCata
 
-instance Functor f => Recursive (->) (Cofree f a) (EnvT a f) where
-  cata = flip Unsafe.hylo project
+instance (Functor f) => Recursive (->) (Cofree f a) (EnvT a f) where
+  cata = Unsafe.unsafeCata
 
-instance Functor f => Recursive (->) (Free f a) (FreeF f a) where
-  cata = flip Unsafe.hylo project
+instance (Functor f) => Recursive (->) (Free f a) (FreeF f a) where
+  cata = Unsafe.unsafeCata
 
 -- TODO: If we can generalize this to an arbitrary 'Recursive (->) t (FreeF h a)'
 --       then it would no longer be unsafe.
-seqFreeT
-  :: (Functor f, Functor h)
-  => DistributiveLaw (->) h f
-  -> DistributiveLaw (->) (Free h) f
+seqFreeT ::
+  (Functor f, Functor h) =>
+  DistributiveLaw (->) h f ->
+  DistributiveLaw (->) (Free h) f
 seqFreeT k =
   cata
-  (\case
-      Pure a -> free . Pure <$> a
-      Free ft -> free . Free <$> k ft)
+    ( \case
+        Pure a -> free . Pure <$> a
+        Free ft -> free . Free <$> k ft
+    )
+
+-- | `fromList` in this instance is unsafe, but `fromListN` is safe, because we
+--   have a finite length to fold.
+--
+--   This means that most uses of @OverloadedLists@ should be fine, but not the
+--   range (`..`) syntax.
+instance IsList (Fix (XNor a)) where
+  type Item (Fix (XNor a)) = a
+  fromList = unsafeFromList
+  fromListN = fromListN
+  toList = toList
+
+-- | `fromList` in this instance is unsafe, but `fromListN` is safe, because we
+--   have a finite length to fold.
+--
+--   This means that most uses of @OverloadedLists@ should be fine, but not the
+--   range (`..`) syntax.
+instance IsList (Mu (XNor a)) where
+  type Item (Mu (XNor a)) = a
+  fromList = unsafeFromList
+  fromListN = fromListN
+  toList = toList
diff --git a/src/Yaya/Unsafe/Zoo.hs b/src/Yaya/Unsafe/Zoo.hs
--- a/src/Yaya/Unsafe/Zoo.hs
+++ b/src/Yaya/Unsafe/Zoo.hs
@@ -1,65 +1,104 @@
-module Yaya.Unsafe.Zoo where
+{-# LANGUAGE Safe #-}
 
-import           Control.Arrow
-import           Control.Comonad.Cofree
-import           Control.Comonad.Env
-import           Control.Monad.Trans.Free
-import           Data.Functor.Compose
-import           Data.Functor.Identity
-import           Data.Bitraversable
+module Yaya.Unsafe.Zoo
+  ( chrono,
+    codyna,
+    coelgot,
+    cotraverse,
+    dyna,
+    elgot,
+    fstream,
+    futu,
+    gpostpro,
+    gprepro,
+    stream,
+    zygoHistoPrepro,
+  )
+where
 
-import           Yaya.Fold
-import           Yaya.Fold.Native
-import           Yaya.Pattern
-import qualified Yaya.Unsafe.Fold as Unsafe
-import qualified Yaya.Unsafe.Fold.Instances as Unsafe -- NB: extremely unsafe
+import "base" Control.Applicative (Applicative (pure))
+import "base" Control.Category (Category (id, (.)))
+import "base" Control.Monad (Monad)
+import "base" Data.Bifunctor (Bifunctor (second))
+import "base" Data.Bitraversable (Bitraversable (bitraverse))
+import "base" Data.Function (const, flip)
+import "base" Data.Functor (Functor (fmap))
+import "base" Data.Functor.Compose (Compose (Compose, getCompose))
+import "base" Data.Functor.Identity (Identity (Identity, runIdentity))
+import "base" Data.Traversable (Traversable)
+import "comonad" Control.Comonad (Comonad)
+import "comonad" Control.Comonad.Env (EnvT)
+import "free" Control.Comonad.Cofree (Cofree)
+import "free" Control.Monad.Trans.Free (Free)
+import "yaya" Yaya.Fold
+  ( Algebra,
+    Coalgebra,
+    Corecursive (ana),
+    DistributiveLaw,
+    ElgotAlgebra,
+    ElgotCoalgebra,
+    GAlgebra,
+    GCoalgebra,
+    Projectable (project),
+    Recursive (cata),
+    Steppable (embed),
+    distEnvT,
+    distIdentity,
+    gana,
+    seqIdentity,
+  )
+import "yaya" Yaya.Fold.Common (diagonal, fromEither)
+import "yaya" Yaya.Fold.Native (distCofreeT)
+import "yaya" Yaya.Pattern (Either, Maybe (Nothing), Pair ((:!:)), XNor (Both, Neither))
+import qualified "this" Yaya.Unsafe.Fold as Unsafe
+import qualified "this" Yaya.Unsafe.Fold.Instances as Unsafe -- FIXME: extremely unsafe
 
-chrono
-  :: Functor f
-  => GAlgebra (->) (Cofree f) f b
-  -> GCoalgebra (->) (Free f) f a
-  -> a
-  -> b
+chrono ::
+  (Functor f) =>
+  GAlgebra (->) (Cofree f) f b ->
+  GCoalgebra (->) (Free f) f a ->
+  a ->
+  b
 chrono = Unsafe.ghylo (distCofreeT id) (Unsafe.seqFreeT id)
 
-codyna :: Functor f => Algebra (->) f b -> GCoalgebra (->) (Free f) f a -> a -> b
+codyna :: (Functor f) => Algebra (->) f b -> GCoalgebra (->) (Free f) f a -> a -> b
 codyna φ = Unsafe.ghylo distIdentity (Unsafe.seqFreeT id) (φ . fmap runIdentity)
 
 -- | [Recursion Schemes for Dynamic Programming](https://www.researchgate.net/publication/221440162_Recursion_Schemes_for_Dynamic_Programming)
-dyna :: Functor f => GAlgebra (->) (Cofree f) f b -> Coalgebra (->) f a -> a -> b
+dyna :: (Functor f) => GAlgebra (->) (Cofree f) f b -> Coalgebra (->) f a -> a -> b
 dyna φ ψ = Unsafe.ghylo (distCofreeT id) seqIdentity φ (fmap Identity . ψ)
 
 -- | Unlike most `Unsafe.hylo`s, `elgot` composes an algebra and coalgebra in a
 --   way that allows information to move between them. The coalgebra can return,
 --   effectively, a pre-folded branch, short-circuiting parts of the process.
-elgot :: Functor f => Algebra (->) f b -> ElgotCoalgebra (->) (Either b) f a -> a -> b
-elgot φ ψ = Unsafe.hylo ((id ||| φ) . getCompose) (Compose . ψ)
+elgot :: (Functor f) => Algebra (->) f b -> ElgotCoalgebra (->) (Either b) f a -> a -> b
+elgot φ ψ = Unsafe.hylo (fromEither . second φ . getCompose) (Compose . ψ)
 
 -- | The dual of `elgot`, `coelgot` allows the /algebra/ to short-circuit in
 --   some cases – operating directly on a part of the seed.
-coelgot :: Functor f => ElgotAlgebra (->) ((,) a) f b -> Coalgebra (->) f a -> a -> b
-coelgot φ ψ = Unsafe.hylo (φ . getCompose) (Compose . (id &&& ψ))
+coelgot :: (Functor f) => ElgotAlgebra (->) (Pair a) f b -> Coalgebra (->) f a -> a -> b
+coelgot φ ψ = Unsafe.hylo (φ . getCompose) (Compose . second ψ . diagonal)
 
 futu :: (Corecursive (->) t f, Functor f) => GCoalgebra (->) (Free f) f a -> a -> t
 futu = gana (Unsafe.seqFreeT id)
 
-gprepro
-  :: (Steppable (->) t f, Recursive (->) t f, Functor f, Comonad w)
-  => DistributiveLaw (->) f w
-  -> GAlgebra (->) w f a
-  -> (forall x. f x -> f x)
-  -> t
-  -> a
+gprepro ::
+  (Steppable (->) t f, Recursive (->) t f, Functor f, Comonad w) =>
+  DistributiveLaw (->) f w ->
+  GAlgebra (->) w f a ->
+  (forall x. f x -> f x) ->
+  t ->
+  a
 gprepro k φ e =
   Unsafe.ghylo k seqIdentity φ (fmap (Identity . cata (embed . e)) . project)
 
-gpostpro
-  :: (Steppable (->) t f, Corecursive (->) t f, Functor f, Monad m)
-  => DistributiveLaw (->) m f
-  -> (forall x. f x -> f x)
-  -> GCoalgebra (->) m f a
-  -> a
-  -> t
+gpostpro ::
+  (Steppable (->) t f, Corecursive (->) t f, Functor f, Monad m) =>
+  DistributiveLaw (->) m f ->
+  (forall x. f x -> f x) ->
+  GCoalgebra (->) m f a ->
+  a ->
+  t
 gpostpro k e =
   Unsafe.ghylo distIdentity k (embed . fmap (ana (e . project) . runIdentity))
 
@@ -69,22 +108,24 @@
 
 -- | Basically the definition from Gibbons’ paper, except the flusher (@h@) is a
 --  `Coalgebra` instead of an `unfold`.
-fstream
-  :: Coalgebra (->) (XNor c) b
-  -> (b -> a -> b)
-  -> Coalgebra (->) (XNor c) b
-  -> b
-  -> [a]
-  -> [c]
+fstream ::
+  Coalgebra (->) (XNor c) b ->
+  (b -> a -> b) ->
+  Coalgebra (->) (XNor c) b ->
+  b ->
+  [a] ->
+  [c]
 fstream f g h =
   Unsafe.streamGApo
-  h
-  (\b -> case f b of
-           Neither -> Nothing
-           other   -> Just other)
-  (\case
-      Neither   -> Nothing
-      Both a x' -> Just (flip g a, x'))
+    h
+    ( \b -> case f b of
+        Neither -> Nothing
+        other -> pure other
+    )
+    ( \case
+        Neither -> Nothing
+        Both a x' -> pure (flip g a :!: x')
+    )
 
 -- snoc :: [a] -> a -> [a]
 -- snoc x a = x ++ [a]
@@ -93,24 +134,24 @@
 -- x = stream project snoc [] [1, 2, 3, 4, 5]
 
 -- TODO: Weaken `Monad` constraint to `Applicative`.
-cotraverse
-  :: ( Steppable (->) t (f a)
-     , Steppable (->) u (f b)
-     , Corecursive (->) u (f b)
-     , Bitraversable f
-     , Traversable (f b)
-     , Monad m)
-  => (a -> m b)
-  -> t
-  -> m u
+cotraverse ::
+  ( Steppable (->) t (f a),
+    Steppable (->) u (f b),
+    Bitraversable f,
+    Traversable (f b),
+    Monad m
+  ) =>
+  (a -> m b) ->
+  t ->
+  m u
 cotraverse f = Unsafe.anaM (bitraverse f pure . project)
 
 -- | Zygohistomorphic prepromorphism – everyone’s favorite recursion scheme joke.
-zygoHistoPrepro
-  :: (Steppable (->) t f, Recursive (->) t f, Functor f)
-  => (f b -> b)
-  -> (f (EnvT b (Cofree f) a) -> a)
-  -> (forall c. f c -> f c)
-  -> t
-  -> a
+zygoHistoPrepro ::
+  (Steppable (->) t f, Recursive (->) t f, Functor f) =>
+  (f b -> b) ->
+  (f (EnvT b (Cofree f) a) -> a) ->
+  (forall c. f c -> f c) ->
+  t ->
+  a
 zygoHistoPrepro φ' = gprepro (distEnvT φ' (distCofreeT id))
diff --git a/tests/doctests.hs b/tests/doctests.hs
new file mode 100644
--- /dev/null
+++ b/tests/doctests.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE Unsafe #-}
+
+module Main (main) where
+
+import "base" Data.Function (($))
+import "base" Data.Semigroup (Semigroup ((<>)))
+import "base" System.IO (IO)
+import "doctest" Test.DocTest (doctest)
+import "this" Build_doctests (flags, module_sources, pkgs)
+
+main :: IO ()
+main = doctest $ flags <> pkgs <> module_sources
diff --git a/yaya-unsafe.cabal b/yaya-unsafe.cabal
--- a/yaya-unsafe.cabal
+++ b/yaya-unsafe.cabal
@@ -1,52 +1,214 @@
-name:                yaya-unsafe
-version:             0.2.0.1
-synopsis:            Non-total extensions to the Yaya recursion scheme library.
-description:         Yaya is designed as a _total_ library. However, it is often
-                     expedient to use partial operations in some cases, and this
-                     package extends Yaya to provide those operations. It’s in a
-                     separate package (and modules) in order to make sure its
-                     use is very intentional and also relatively obvious to
-                     those reading your code. It’s recommended that you import
-                     these modules qualified and, in particular, all the type
-                     class instances here have been pulled into a separate
-                     module to avoid accidentally bringing them into scope.
-homepage:            https://github.com/sellout/yaya#readme
-author:              Greg Pfeil
-maintainer:          greg@technomadic.org
-copyright:           2017 Greg Pfeil
-license:             AGPL-3
-license-file:        LICENSE
-category:            Recursion
-build-type:          Simple
-extra-source-files:  CHANGELOG.md
-                   , README.md
-cabal-version:       >=1.10
+cabal-version:  3.0
 
-library
-  hs-source-dirs:      src
-  exposed-modules:     Yaya.Unsafe.Fold
-                     , Yaya.Unsafe.Fold.Instances
-                     , Yaya.Unsafe.Zoo
-  build-depends:       base >= 4.7 && < 5
-                     , bifunctors
-                     , comonad
-                     , either
-                     , free
-                     , lens
-                     , yaya >= 0.3.0
-  default-extensions:  ConstraintKinds
-                     , DeriveTraversable
-                     , FlexibleContexts
-                     , FlexibleInstances
-                     , FunctionalDependencies
-                     , LambdaCase
-                     , MultiParamTypeClasses
-                     , RankNTypes
-                     , ScopedTypeVariables
-                     , StrictData
-                     , TupleSections
-  default-language:    Haskell2010
+name:        yaya-unsafe
+version:     0.3.3.0
+synopsis:    Non-total extensions to the Yaya recursion scheme library.
+description: Yaya is designed as a _total_ library. However, it is often
+             expedient to use partial operations in some cases, and this package
+             extends Yaya to provide those operations. It’s in a separate
+             package (and modules) in order to make sure its use is very
+             intentional and also relatively obvious to those reading your code.
+             It’s recommended that you import these modules qualified and, in
+             particular, all the type class instances here have been pulled into
+             a separate module to avoid accidentally bringing them into scope.
+author:      Greg Pfeil <greg@technomadic.org>
+maintainer:  Greg Pfeil <greg@technomadic.org>
+copyright:   2017 Greg Pfeil
+homepage:    https://github.com/sellout/yaya#readme
+bug-reports: https://github.com/sellout/yaya/issues
+category:    Recursion
+build-type:  Custom
+license:     AGPL-3.0-or-later
+license-files:
+  LICENSE
+extra-source-files:
+  CHANGELOG.md
+  README.md
+tested-with:
+  GHC == {
+--  GHCup   Nixpkgs
+    8.6.1,
+    8.8.1,  8.8.4,
+    8.10.1,
+    9.0.1,
+    9.2.1,
+    9.4.1,  9.4.8,
+    9.6.1,
+            9.8.1
+  }
 
 source-repository head
-  type:     git
+  type: git
   location: https://github.com/sellout/yaya
+
+-- This mimics the GHC2021 extension
+-- (https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/control.html?highlight=doandifthenelse#extension-GHC2021),
+-- but supporting compilers back to GHC 7.10. If the oldest supported compiler
+-- is GHC 9.2, then this stanza can be removed and `import: GHC2021` can be
+-- replaced by `default-language: GHC2021`.
+common GHC2021
+  default-language: Haskell2010
+  default-extensions:
+    BangPatterns
+    BinaryLiterals
+    ConstraintKinds
+    DeriveDataTypeable
+    DeriveGeneric
+    -- DeriveLift -- uncomment if the oldest supported version is GHC 8.10.1+
+    DeriveTraversable
+    DerivingStrategies
+    DoAndIfThenElse
+    EmptyCase
+    ExistentialQuantification
+    FlexibleContexts
+    FlexibleInstances
+    GADTSyntax
+    GeneralizedNewtypeDeriving
+    HexFloatLiterals
+    -- ImportQualifiedPost -- uncomment if the oldest supported version is GHC 8.10.1+
+    InstanceSigs
+    LambdaCase
+    MagicHash
+    MonadComprehensions
+    MonomorphismRestriction
+    MultiParamTypeClasses
+    NamedFieldPuns
+    NamedWildCards
+    NumericUnderscores
+    PolyKinds
+    PostfixOperators
+    RankNTypes
+    ScopedTypeVariables
+    StandaloneDeriving
+    -- StandaloneKindSignatures -- uncomment if the oldest supported version is GHC 8.10.1+
+    TupleSections
+    TypeApplications
+    TypeOperators
+    UnicodeSyntax
+    NoExplicitNamespaces
+
+common defaults
+  import: GHC2021
+  build-depends:
+    base ^>= {4.12.0, 4.13.0, 4.14.0, 4.15.0, 4.16.0, 4.17.0, 4.18.0, 4.19.0},
+  ghc-options:
+    -Weverything
+    -- Type inference good.
+    -Wno-missing-local-signatures
+    -- Warns even when `Unsafe` is explicit, not inferred. See
+    -- https://gitlab.haskell.org/ghc/ghc/-/issues/16689
+    -Wno-unsafe
+    -- TODO: prune these warnings
+    -Wno-all-missed-specialisations
+    -fpackage-trust
+    -trust base
+  if impl(ghc < 8.8.1)
+    ghc-options:
+      -- This used to warn even when `Safe` was explicit.
+      -Wno-safe
+  if impl(ghc >= 8.10.1)
+    ghc-options:
+      -- If we didn’t allow inferred-safe imports, nothing would be `Safe`.
+      -Wno-inferred-safe-imports
+      -- We support GHC versions without qualified-post.
+      -Wno-prepositive-qualified-module
+      -- `-trust` triggers this warning when applied to transitive dependencies.
+      -Wno-unused-packages
+  if impl(ghc >= 9.2.1)
+    ghc-options:
+      -- We support GHC versions without kind signatures.
+      -Wno-missing-kind-signatures
+  if impl(ghc >= 9.8.1)
+    ghc-options:
+      -- We support GHC versions without kind signatures.
+      -Wno-missing-poly-kind-signatures
+      -- Inference good.
+      -Wno-missing-role-annotations
+  default-extensions:
+    DefaultSignatures
+    ExplicitNamespaces
+    FunctionalDependencies
+    LiberalTypeSynonyms
+    -- replace with `LexicalNegation` if the oldest supported version is GHC 9.0.1+
+    NegativeLiterals
+    PackageImports
+    ParallelListComp
+    -- QualifiedDo - uncomment if the oldest supported version is GHC 9.0.1+
+    RecursiveDo
+    -- RequiredTypeArguments - uncomment if the oldest supported version is GHC 9.10.1+
+    RoleAnnotations
+    StrictData
+    TemplateHaskellQuotes
+    TransformListComp
+    NoGeneralizedNewtypeDeriving
+    NoImplicitPrelude
+    NoMonomorphismRestriction
+    NoPatternGuards
+    NoTypeApplications
+
+custom-setup
+  setup-depends:
+    -- TODO: Remove `Cabal` dep once haskell/cabal#3751 is fixed.
+    Cabal ^>= {3.0.0, 3.2.0, 3.4.0, 3.6.0, 3.8.0, 3.10.0},
+    base ^>= {4.12.0, 4.13.0, 4.14.0, 4.15.0, 4.16.0, 4.17.0, 4.18.0, 4.19.0},
+    cabal-doctest ^>= 1.0.0
+
+library
+  import: defaults
+  hs-source-dirs:
+    src
+  exposed-modules:
+    Yaya.Unsafe.Applied
+    Yaya.Unsafe.Fold
+    Yaya.Unsafe.Fold.Instances
+    Yaya.Unsafe.Zoo
+  build-depends:
+    bifunctors,
+    comonad,
+    free,
+    lens,
+    yaya >= 0.5.1,
+  ghc-options:
+    -trust adjunctions
+    -trust array
+    -trust base-orphans
+    -trust binary
+    -trust bytestring
+    -trust containers
+    -trust distributive
+    -trust exceptions
+    -trust ghc-prim
+    -trust lens
+    -trust profunctors
+    -trust semigroupoids
+    -trust stm
+    -trust text
+    -trust transformers-compat
+  if impl(ghc < 9.6)
+    ghc-options:
+      -trust foldable1-classes-compat
+
+test-suite doctests
+  import: defaults
+  type: exitcode-stdio-1.0
+  hs-source-dirs: tests
+  main-is: doctests.hs
+  build-depends:
+    doctest ^>= {0.15.0, 0.16.0, 0.17.0, 0.18.0, 0.19.0, 0.20.0, 0.21.0, 0.22.0},
+    yaya-unsafe,
+  -- TODO: The sections below here are necessary because we don’t have control
+  --       over the generated `Build_doctests.hs` file. So we have to silence
+  --       all of its warnings one way or another.
+  ghc-options:
+    -Wno-missing-export-lists
+    -Wno-missing-import-lists
+    -Wno-safe
+  if impl(ghc >= 8.8.1)
+    ghc-options:
+      -- This used to warn even when `Safe` was explicit.
+      -Wno-missing-deriving-strategies
+  default-extensions:
+    -- Since we can’t add `{-# LANGUAGE Safe -#}` to the generated
+    -- “Build_doctests.hs”, we set it here, and that means it has to match
+    -- doctests.hs, which is `Unsafe`.
+    Unsafe
