diff --git a/COPYING b/COPYING
new file mode 100644
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,25 @@
+Copyright (c) 2009 Conal Elliott
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The names of the authors may not be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,3 @@
 # For special configuration, especially for docs.  Otherwise see README.
 
-include ../my-cabal-make.inc
+include ../cho-home-cabal-make.inc
diff --git a/bot.cabal b/bot.cabal
--- a/bot.cabal
+++ b/bot.cabal
@@ -1,5 +1,5 @@
 Name:                bot
-Version:             0.1
+Version:             0.3
 Synopsis: 	     bots for functional reactive programming
 Category:            reactivity, FRP
 Description:
@@ -12,25 +12,32 @@
   to wiki pages where you can read and contribute user comments.  Enjoy!
   .
   &#169; 2008 by Conal Elliott; BSD3 license.
+Cabal-Version:       >= 1.2
 Author:              Conal Elliott 
 Maintainer:          conal@conal.net
 Homepage:            http://haskell.org/haskellwiki/Bot
-Package-Url:	     http://darcs.haskell.org/packages/bot
-Copyright:           (c) 2007-2008 by Conal Elliott
+Package-Url:	     http://code.haskell.org/~conal/code/bot
+Copyright:           (c) 2007-2010 by Conal Elliott
 License:             BSD3
+License-File:        COPYING
+build-type:          Simple
 Stability:           experimental
-Hs-Source-Dirs:      src
-Extensions:          
-Build-Depends:       base, arrows, Stream
-Exposed-Modules:     
-		     Data.Bot.Mutant
-		     Data.Bot.Misc
-		     Data.Bot.Chatter
-		     Data.Bot.LeadFollow
 Extra-Source-Files:
-		     Examples.Chatter
-		     Examples.LeadFollow
-ghc-options:         -Wall -O
+                     Examples.Chatter
+                     Examples.LeadFollow
+
+Library
+  Hs-Source-Dirs:      src
+  Extensions:          
+  Build-Depends:       base >= 4 && < 5, arrows >= 0.4, Stream
+  Exposed-Modules:     
+                       Data.Bot.Mutant
+                       Data.Bot.Misc
+                       Data.Bot.Chatter
+                       Data.Bot.LeadFollow
+                       Data.Bot.Edit
+  ghc-options:         -Wall
+
 
 -- We could add TypeCompose to Build-Depends and uncomment the Pair instances
 -- in Data.Bot.LeadFollow.
diff --git a/src/Data/Bot/Chatter.hs b/src/Data/Bot/Chatter.hs
--- a/src/Data/Bot/Chatter.hs
+++ b/src/Data/Bot/Chatter.hs
@@ -21,7 +21,9 @@
   , justC, filterC, scanlC, accumC
   ) where
 
-import Control.Arrow hiding (pure)
+import Prelude hiding (id,(.))
+import Control.Category
+import Control.Arrow
 import Control.Applicative
 import Data.Monoid
 import Data.Maybe
@@ -31,15 +33,31 @@
 
 -- | Chatter-bots.  Can have any number of outputs per input.  'mappend'
 -- appends outputs.
-newtype ChatterBot i o =
-  Chatter { unChatter :: MutantBot i [o] } deriving Monoid
+newtype ChatterBot i o = Chatter { unChatter :: MutantBot i [o] }
 
+instance Monoid (ChatterBot i o) where
+  mempty = Chatter (pure mempty)
+  Chatter b `mappend` Chatter c = Chatter (liftA2 mappend b c)
+
+instance Category ChatterBot where
+  id = arr id
+  Chatter bc . Chatter ab = Chatter (concatMB bc . ab)
+
 instance Arrow ChatterBot where
   arr h = Chatter (arr (pure . h))
-  Chatter ab >>> Chatter bc = Chatter (ab >>> concatMB bc)
   first (Chatter f) = Chatter $
     first f >>> arr (\ (bs,c) -> [(b,c) | b <- bs])
     -- first f >>> arr (\ (bs,c) -> fmap (flip (,) c) bs)
+
+instance ArrowZero ChatterBot where
+  zeroArrow = mempty
+
+instance ArrowPlus ChatterBot where
+  (<+>) = mappend
+
+instance Alternative (ChatterBot i) where
+  empty = mempty
+  (<|>) = mappend
 
 -- Boilerplate Functor & Applicative for Arrow instance
 
diff --git a/src/Data/Bot/Edit.hs b/src/Data/Bot/Edit.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bot/Edit.hs
@@ -0,0 +1,179 @@
+{-# OPTIONS -Wall #-}
+{-# LANGUAGE GADTs, KindSignatures, TypeOperators, GeneralizedNewtypeDeriving
+  , ScopedTypeVariables, Arrows #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  Data.Bot.Edit
+-- Copyright   :  (c) Conal Elliott 2008
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- Edit-bots
+----------------------------------------------------------------------
+
+module Data.Bot.Edit where
+
+import Prelude hiding (id,(.))
+import Control.Category
+import Control.Arrow
+
+import Data.Maybe (fromMaybe)
+
+-- import Control.Arrow.Transformer
+import Control.Arrow.Transformer.Automaton
+
+import Data.Stream hiding ()
+import qualified Data.Stream as S
+
+-- | An edit/change to a value.  Represents @a -> a@ but as data, to allow
+-- analysis.
+data Edit :: * -> * where
+  Konst   :: a -> Edit a                     -- const
+  Idy     :: Edit a                          -- id
+  (:***)  :: Edit a -> Edit b -> Edit (a,b)  -- ***
+  (:>>>)  :: Edit a -> Edit a -> Edit a      -- (>>>)
+
+-- Note: why use *** instead of First?  Because the smart constructor
+-- rewrite rules seem to come out more simply.
+
+-- | Interpret an edit as an arrow value (e.g., function).
+edit :: Arrow (~>) => Edit a -> (a ~> a)
+edit (Konst a)      = arr (const a)
+edit Idy            = arr id
+edit (eda :*** edb) = edit eda *** edit edb
+edit (ed :>>> ed')  = edit ed  >>> edit ed'
+
+-- TODO: import Data.Pair.  Replace unzip* with unpair and zip* with
+-- pair.  Would add a TypeCompose dependency.
+
+-- | Zip up two edits into a pair edit
+zipE :: Edit a -> Edit b -> Edit (a,b)
+zipE = (***:)
+
+-- Try splitting one edit @ed@ into two independent edits @eda@ and @edb@
+-- such that @ed == eda *** edb@.
+unzipE :: Edit (a,b) -> Maybe (Edit a, Edit b)
+
+unzipE (Konst (a,b))  = Just (Konst a, Konst b)
+unzipE Idy            = Just (Idy, Idy)
+unzipE (eda :*** edb) = Just (eda, edb)
+unzipE (_   :>>> _  ) = Nothing
+
+-- | Smart constructor for '(:***)'.  Applies some rewrites.
+(***:) :: Edit a -> Edit b -> Edit (a,b)
+
+Idy     ***: Idy     = Idy
+Konst a ***: Konst b = Konst (a,b)
+ed      ***: ed'     = ed :*** ed'
+
+-- | Smart constructor for '(:>>>)'.  Applies some rewrites.
+(>>>:) :: Edit a -> Edit a -> Edit a
+
+Idy        >>>: f            = f
+f          >>>: Idy          = f
+_          >>>: k@(Konst _)  = k
+(f :*** g) >>>: (f' :*** g') = (f >>>: f') ***: (g >>>: g')
+ed         >>>: ed'          = ed :>>> ed'
+
+
+-- | A tweak is an edit and a new value.  This new value can be computed
+-- from the edit and a previous value.  It's stored here (lazily) so it
+-- can be shared.
+data Tweak a = Tweak (Edit a) a
+
+-- | Simple 'Konst' tweaker.  A catch-all, but not helpful for performance.
+tweak :: a -> Tweak a
+tweak a = Tweak (Konst a) a
+
+-- Zip up two tweaks into a pair tweak.
+zipT :: Tweak a -> Tweak b -> Tweak (a,b)
+zipT (Tweak ea a) (Tweak eb b) = Tweak (zipE ea eb) (a,b)
+
+-- | Split a pair tweak in two.
+unzipT :: Tweak (a,b) -> (Tweak a, Tweak b)
+unzipT (Tweak ed (a,b)) = (Tweak eda a, Tweak edb b)
+ where
+   (eda,edb) = fromMaybe (Konst a, Konst b) (unzipE ed)
+
+-- | Stream of tweaks
+type Tweaks a = Stream (Tweak a)
+
+-- Zip up two tweak streams into a pair-valued tweak stream.
+zipTs :: Tweaks a -> Tweaks c -> Tweaks (a,c)
+zipTs = (fmap.fmap.fmap) (uncurry zipT) S.zip
+
+-- zipTs tas tcs = fmap (uncurry zipT) $ S.zip tas tcs
+
+-- | Split a pair-valued tweak stream in two.
+unzipTs :: Tweaks (a,c) -> (Tweaks a, Tweaks c)
+unzipTs = S.unzip . fmap unzipT
+
+
+-- | Reactive (discretely varying) value.  An initial value and a stream
+-- of tweaks.  
+-- 
+-- Although 'Reactive' is a 'Functor', I don't recommend its use.  'fmap'
+-- cannot do much optimization without knowing something about the
+-- function being mapped.  Maybe better not to have the 'Functor'
+-- instance.
+data Reactive a = R a (Tweaks a)
+
+-- Maybe punt Reactive and rely on the first stream element to have a Konst
+
+instance Functor Reactive where
+  fmap f (R a ts) = R b (fmapR' f b ts) where b = f a
+
+-- Carry value along to re-use for identity edits.
+fmapR' :: (a -> b) -> b -> Stream (Tweak a) -> Stream (Tweak b)
+fmapR' f b (Cons (Tweak Idy _) ts) = Cons (Tweak Idy b) (fmapR' f b ts)
+fmapR' f _ (Cons (Tweak _ a) ts) =
+  Cons (tweak b') (fmapR' f b' ts) where b' = f a
+
+-- | Zip up two reactive values into a reactive pair.
+zipR :: Reactive a -> Reactive c -> Reactive (a,c)
+zipR (R a tas) (R c tcs) = R (a,c) (zipTs tas tcs)
+
+-- | Split a reactive pair into a pair of reactive values.
+unzipR :: Reactive (a,c) -> (Reactive a, Reactive c)
+unzipR (R (a,c) ts) = (R a tsa, R c tsc)
+ where
+   (tsa,tsc) = unzipTs ts
+
+
+-- | Arrow between two reactive values.
+newtype ArrowReactive (~>) a b = AR (Reactive a ~> Reactive b)
+
+instance Category (~>) => Category (ArrowReactive (~>)) where
+  id          = AR id
+  AR g . AR f = AR (g . f)
+
+instance Arrow (~>) => Arrow (ArrowReactive (~>)) where
+  arr f         = AR (arr (fmap f))
+  first (AR  f) = AR (arr unzipR >>> first f >>> arr (uncurry zipR))
+
+
+-- | 'Automaton'-style tweak arrow.  Could be split into follow and lead.
+data AutR (~>) a b = AutR (a ~> (b, Automaton (~>) (Tweak a) (Tweak b)))
+
+instance Arrow (~>) => Category (AutR (~>)) where
+  id = arr id
+  AutR g . AutR f = AutR $ proc a -> do (b,ab) <- f -< a
+                                        (c,bc) <- g -< b
+                                        returnA -< (c, bc . ab)
+
+instance Arrow (~>) => Arrow (AutR (~>)) where
+  arr f = AutR (arr (\ a -> let b = f a in (b, arrAut f (f a))))
+  first (AutR f) = AutR $
+    proc (a,c) ->
+      do (b,ab) <- f -< a
+         returnA -< ((b,c), arr unzipT >>> first ab >>> arr (uncurry zipT))
+
+arrAut :: Arrow (~>) => (a -> b) -> b -> Automaton (~>) (Tweak a) (Tweak b)
+arrAut f b = aut
+ where
+   aut = Automaton (arr g)
+   g (Tweak Idy _) = (Tweak Idy b, aut)
+   g (Tweak _   a) = (tweak b', arrAut f b') where b' = f a
+
diff --git a/src/Data/Bot/LeadFollow.hs b/src/Data/Bot/LeadFollow.hs
--- a/src/Data/Bot/LeadFollow.hs
+++ b/src/Data/Bot/LeadFollow.hs
@@ -29,8 +29,11 @@
   , editPairL, editPairF
   ) where
 
+import Prelude hiding (id,(.))
 import Control.Applicative
-import Control.Arrow hiding (pure)
+import Control.Category
+
+import Control.Arrow
 import Data.Maybe (maybeToList)
 import Data.Monoid
 
@@ -95,13 +98,17 @@
 -- through newtypes in this case.
 
 -- Adapted from the Automaton Arrow instance
-instance Arrow Follow where
-  arr f = foll where foll = Follow (\ a -> Lead (f a, foll))
-  Follow f >>> Follow g = Follow $
+
+instance Category Follow where
+  id = arr id
+  Follow g . Follow f = Follow $
     f >>>
     arr unLead >>>
     first g >>>
-    arr (\ (Lead (z, cg), cf) -> Lead (z, cf >>> cg))
+    arr (\ (Lead (z, cg), cf) -> Lead (z, cg . cf))
+
+instance Arrow Follow where
+  arr f = foll where foll = Follow (\ a -> Lead (f a, foll))
   first (Follow f) = Follow $
     first f >>>
     arr (\(Lead (x', c), y) -> Lead ((x', y), first c))
@@ -153,9 +160,12 @@
 -- | Start out following (multi-output)
 newtype a :-> b = Follows { unFollows :: Follow a [b] } deriving Monoid
 
+instance Category (:->) where
+  id = arr id
+  Follows bc . Follows ab = Follows (concatMB bc . ab)
+
 instance Arrow (:->) where
   arr h = Follows (arr (pure . h))
-  Follows ab >>> Follows bc = Follows (ab >>> concatMB bc)
   first (Follows f) = Follows $
     first f >>> arr (\ (bs,c) -> [(b,c) | b <- bs])
     -- first f >>> arr (\ (bs,c) -> fmap (flip (,) c) bs)
diff --git a/src/Data/Bot/Misc.hs b/src/Data/Bot/Misc.hs
--- a/src/Data/Bot/Misc.hs
+++ b/src/Data/Bot/Misc.hs
@@ -21,10 +21,9 @@
   ) where
 
 import Data.Monoid
-import Control.Arrow hiding (pure)
 import Control.Applicative
 
-import Data.Stream hiding (zip,unzip,map,scanl,tail)
+import Data.Stream hiding (zip,unzip,map,tail)
 
 import Control.Arrow.Transformer.Stream
 
@@ -34,13 +33,13 @@
 -- and 'Applicative' (partially applied for the latter two).
 type StreamBot = StreamArrow (->)
 
-deriving instance Monoid o => Monoid (StreamBot i o)
-
-
 -- | Bots who can choose whether or not to react to an input.  The
 -- 'mappend' operation is left-biased in case of simultaneous reaction.
-newtype ChoosyBot i o = Choosy (MutantBot i (First o)) deriving Monoid
+newtype ChoosyBot i o = Choosy (MutantBot i (First o))
 
+instance Monoid (ChoosyBot i o) where
+  mempty = Choosy (pure mempty)
+  Choosy b `mappend` Choosy c = Choosy (liftA2 mappend b c)
 
 ---- Move elsewhere
 
@@ -49,12 +48,3 @@
 instance Monoid o => Monoid (Stream o) where
   mempty  = pure   mempty
   mappend = liftA2 mappend
-
-
--- Standard Functor & Applicative instances for arrows.  See WrappedArrow.
-
-instance Arrow (~>) => Functor (StreamArrow (~>) i) where fmap = (^<<)
-
-instance Arrow (~>) => Applicative (StreamArrow (~>) i) where
-  pure x        = arr (const x)
-  fbot <*> xbot = fbot &&& xbot >>> arr (uncurry ($))
diff --git a/src/Data/Bot/Mutant.hs b/src/Data/Bot/Mutant.hs
--- a/src/Data/Bot/Mutant.hs
+++ b/src/Data/Bot/Mutant.hs
@@ -20,9 +20,7 @@
     MutantBot, steps, concatMB, scanlM, accumM
   ) where
 
-import Control.Arrow hiding (pure)
-import Control.Applicative
-import Data.Monoid
+import Control.Arrow
 
 import Control.Arrow.Transformer.Automaton
 
@@ -33,10 +31,6 @@
 -- Isomorphic to @a -> (b, a -> (b, a -> (b, ...)))@
 type MutantBot = Automaton (->)
 
-instance Monoid o => Monoid (MutantBot i o) where
-  mempty  = pure   mempty
-  mappend = liftA2 mappend
-
 -- | Perform multiple steps, yielding the collected outputs and residual bot.
 steps :: ([i], MutantBot i o) -> ([o], MutantBot i o)
 steps (is,bot) =
@@ -75,13 +69,3 @@
 
 -- or
 -- accum a = tail . scanl (flip ($)) a
-
-
----- Move elsewhere
-
-instance Arrow (~>) => Functor (Automaton (~>) i) where fmap = (^<<)
-
-instance Arrow (~>) => Applicative (Automaton (~>) i) where
-  pure x        = arr (const x)
-  fbot <*> xbot = fbot &&& xbot >>> arr (uncurry ($))
-
diff --git a/src/Data/Bot/Part.hs b/src/Data/Bot/Part.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bot/Part.hs
@@ -0,0 +1,218 @@
+{-# LANGUAGE MagicHash, GADTs, KindSignatures, ScopedTypeVariables
+           , Rank2Types #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  Data.Bot.Part
+-- Copyright   :  (c) Conal Elliott 2008
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- 
+----------------------------------------------------------------------
+
+module Data.Bot.Part where
+
+import Control.Arrow hiding (pure)
+import Control.Applicative
+import Data.Maybe (fromMaybe)
+import GHC.Base (unsafeCoerce#) -- used in partMatch and coerceV
+
+-- | Part of a structure of nested pairs
+data Part :: * -> * -> * where
+  IdP     :: Part a a
+  FirstP  :: Part c a -> Part (c,b) a
+  SecondP :: Part c b -> Part (a,c) b
+
+-- | Equality on parts
+partEq :: Part i a -> Part i b -> Bool
+IdP       `partEq` IdP       = True
+FirstP  p `partEq` FirstP  q = p `partEq` q
+SecondP p `partEq` SecondP q = p `partEq` q
+_         `partEq` _         = False
+ 
+-- | Leibniz equality
+type Leibniz a a' = forall phi. phi a -> phi a'
+
+--newtype Leibniz a a' = Leibniz (forall phi. phi a -> phi a')
+
+-- | Try to match parts.  If successful, yield a proof of Leibniz
+-- equality, i.e., a coercion.
+partMatch :: Part c a -> Part c a' -> Maybe (Leibniz a a')
+a `partMatch` a' 
+  | a `partEq` a' = Just unsafeCoerce#
+  | otherwise     = Nothing
+
+
+-- | Extract part of a value.  Use staged to avoid interpretive overhead.
+extract :: Part c a -> (c -> a)
+extract IdP         = id
+extract (FirstP  p) = extract p . fst
+extract (SecondP p) = extract p . snd
+
+-- | Change a part of a value.  Use staged to avoid interpretive overhead.
+change :: Part c a -> ((a -> a) -> (c -> c))
+change IdP         = id
+change (FirstP  p) = first  . change p
+change (SecondP p) = second . change p
+
+-- I really only wanted constant @a@ values for 'change', but I like how the
+-- definition mirrors @comp@'s in this slightly more general setting.
+-- Also, 'extract' and 'change' relate 'Part' to composable references.
+
+-- | Substitute for part of a value.  Use staged to avoid interpretive overhead.
+subst :: Part c a -> (a -> (c -> c))
+subst p = change p . const
+
+-- About the staging comments:
+-- 
+-- Because of the way I've defined 'extract', 'change', and 'subst',
+-- the "syntactic" analysis of parts is done once rather than at each
+-- substitution.  The extra parentheses in the type signature serve as
+-- a reminder.  Will haddock remove the extra parens?
+
+
+-- | Compose parts.  Specification:
+-- 
+-- @extract (comp p q) == extract q . extract p@
+-- @change  (comp p q) == change  p . change  q@
+comp :: Part c b -> (Part b a -> Part c a)
+comp IdP         = id
+comp (FirstP  p) = FirstP  . comp p
+comp (SecondP p) = SecondP . comp p
+
+-- comp IdP         q = q
+-- comp (FirstP  p) q = FirstP  (comp p q)
+-- comp (SecondP p) q = SecondP (comp p q)
+
+--    extract (comp (FirstP p) q) 
+-- == extract q . extract (FirstP p)
+-- == extract q . extract p . fst
+-- == extract (FirstP (comp p q))
+
+-- change p ::(b -> b) -> (c -> c)
+-- change q ::(a -> a) -> (b -> b)
+-- change p . change q :: (a -> a) -> (c -> c)
+
+--    change (comp (FirstP p) q)
+-- == change (FirstP p) . change q
+-- == first . change p . change q
+-- == first . change (comp p q)
+-- == change (FirstP (comp p q))
+
+
+---- experiments
+
+-- \ ((a,b),c) -> a*b + b*c
+t1 :: ((Int,Int),Int) -> Int
+t1 = liftA2 (+)
+       (liftA2 (*) (fst>>>fst) (fst>>>snd))
+       (liftA2 (*) (fst>>>snd) snd)
+
+
+
+-- Bot with top-level data
+data DBot i o = DBot o (Bot i o)
+
+-- Bot without top-level data
+data Bot :: * -> * -> * where
+  PureB :: Bot i o
+  AppB  :: DBot i (a -> b) -> DBot i a -> Bot i b
+  PartB :: Part i o -> Bot i o
+
+instance Functor (DBot i) where
+  fmap f = (pure f <*> )
+
+instance Applicative (DBot i) where
+  pure o = DBot o PureB
+  fd@(DBot f _) <*> xd@(DBot x _) = DBot (f x) (fd `AppB` xd)
+
+-- TODO: factor  the Applicative pattern from Bot & DBot.  Parameterize
+-- by @Part i@.  The the general version has just one type argument.
+
+
+-- | An 'Applicative'-style tree of values.
+data AppV :: * -> * where
+  PureV :: a -> AppV a
+  AppV  :: a -> AppV (b -> a) -> AppV b -> AppV a
+
+-- Extract the top-level value from a tree.
+vVal :: AppV a -> a
+vVal (PureV    a) = a
+vVal (AppV a _ _) = a
+
+appV :: AppV (b -> a) -> AppV b -> AppV a
+fv `appV` bv = AppV ((vVal fv) (vVal bv)) fv bv
+
+instance Functor AppV where
+  fmap f = (pure f <*> )
+
+instance Applicative AppV where
+  pure  = PureV
+  (<*>) = appV
+
+data AppF :: (* -> *) -> * -> * where
+  PureF :: a -> AppF h a
+  AppF  :: AppF h (b -> a) -> AppF h b -> AppF h a
+  InF   :: h a -> AppF h a
+
+instance Functor (AppF h) where
+  fmap f = (pure f <*> )
+
+instance Applicative (AppF h) where
+  pure  = PureF
+  (<*>) = AppF
+
+
+-- | Adaptive bot.
+type Adapt i = AppF (Part i)
+
+-- | Evaluate a Adapt at an input, yielding a caching structure that
+-- matches the Adapt's shape.
+eval :: Adapt i o -> i -> AppV o
+eval (PureF a)        = const (PureV a)
+eval (AppF fbot bbot) = liftA2 appV (eval fbot) (eval bbot)
+eval (InF p)          = PureV . extract p
+
+-- A possible means of substituting in an @a@ value.  A 'Nothing' means
+-- that the substitution wouldn't make any change.
+type MbSubst a b = Maybe (a -> AppV b -> AppV b)
+
+-- | Make an update function for a bot.  To eliminate interpretive
+-- overhead, apply 'update' in stages: first provide a bot.  Then each
+-- part in turn.
+update :: Adapt i o -> (Part i a -> MbSubst a o)
+
+update (PureF _) = const Nothing
+
+update (InF p) = \ q -> 
+  case q `partMatch` p of
+    Just coerce -> Just (\ a _ -> coerce (PureV a))
+    Nothing     -> Nothing
+
+update (fun `AppF` arg) = \ q ->
+  case (msubf q, msuba q) of
+    (Nothing,Nothing) -> Nothing
+    (repf,repb)       -> Just $ \ a (AppV _ vf vb) ->
+      upd fun repf a vf `appV` upd arg repb a vb
+ where
+   msubf = update fun
+   msuba = update arg
+
+-- Apply a 'MbSubst' to a value and an 'AppV' that matches the given
+-- 'AppF'.  Warning: this matching requirement is not statically checked,
+-- and Very Bad Things can happen if it's violated.  See 'coerceV'.
+upd :: AppF f b -> MbSubst a b -> a -> AppV b' -> AppV b
+upd appf rep a v' = fromMaybe ((const.const) v) rep a v
+ where
+   v = coerceV appf v'
+
+-- The 'eval' and 'update' functions maintain an invariant that
+-- corresponding 'AppF' and 'AppV' have the same intermediate @b@ type.
+-- This coercion function exploits that invariant.
+-- 
+-- TODO: look for a statically checked alternative.
+coerceV :: AppF f b -> AppV b' -> AppV b
+coerceV = const unsafeCoerce#
diff --git a/src/Examples/Chatter.hs b/src/Examples/Chatter.hs
--- a/src/Examples/Chatter.hs
+++ b/src/Examples/Chatter.hs
@@ -2,7 +2,7 @@
 {-# LANGUAGE TypeOperators, ScopedTypeVariables #-}
 ----------------------------------------------------------------------
 -- |
--- Module      :  Examples.Bot
+-- Module      :  Examples.Chatter
 -- Copyright   :  (c) Conal Elliott 2008
 -- License     :  BSD3
 -- 
@@ -12,14 +12,14 @@
 -- Examples for "Data.Bot.Bot"
 ----------------------------------------------------------------------
 
-module Examples.Bot where
+module Examples.Chatter where
 
-import Control.Arrow hiding (pure)
+import Control.Arrow
 import Control.Arrow.Transformer.Automaton
 import Control.Applicative
 import Data.Monoid
 
-import Data.Bot.Bot
+import Data.Bot.Chatter
 
 
 type a :>- b = (b, a :-> b)
@@ -46,8 +46,10 @@
 -- bot.
 
 updPair :: Either c d -> (c,d) -> (c,d)
-updPair (Left  c') (_,d) = (c',d)
-updPair (Right d') (c,_) = (c,d')
+updPair = (first.const) `either` (second.const)
+
+-- updPair (Left  c') (_,d) = (c',d)
+-- updPair (Right d') (c,_) = (c,d')
 
 pairbot :: (c,d) -> Either c d :>- (c,d)
 pairbot cd = (cd, updPair ^>> accumC cd)
diff --git a/src/Examples/LeadFollow.hs b/src/Examples/LeadFollow.hs
--- a/src/Examples/LeadFollow.hs
+++ b/src/Examples/LeadFollow.hs
@@ -14,8 +14,7 @@
 
 module Examples.LeadFollow where
 
-import Control.Arrow hiding (pure)
-import Control.Applicative
+import Control.Arrow
 import Data.Monoid
 
 import Data.Bot.LeadFollow
