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
new file mode 100644
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,1 @@
+include ../cho-home-cabal-make.inc
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,11 @@
+project-foo [1] is a template for a package, to make it easy to copy &
+modify.  It uses cabal-make [2] for convenience.  It's even equipped with
+a darcs repo.  Copy the directory ("cp -rp"), "darcs mv" and edit the
+.cabal file, edit README and wikipage.tw, and "rm _darcs/prefs/*repo*".
+Then add new content with "make check-add" and "make add-new".  "darcs
+record" the changes.  When ready, do a "darcs put" or "make repo".
+
+References:
+
+[1] http://haskell.org/haskellwiki/project-foo
+
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/functor-combo.cabal b/functor-combo.cabal
new file mode 100644
--- /dev/null
+++ b/functor-combo.cabal
@@ -0,0 +1,42 @@
+Name:                functor-combo
+Version:             0.0.0
+Cabal-Version:       >= 1.2
+Synopsis:            Functor combinators with tries & zippers
+Category:            Data
+Description:
+  Simple functor combinators, their derivatives, and their use for tries
+  Maybe split out derivatives and/or tries later.
+  .
+Author:              Conal Elliott
+Maintainer:          conal@conal.net
+Homepage:            http://haskell.org/haskellwiki/functor-combo
+Copyright:           (c) 2010 by Conal Elliott
+License:             BSD3
+License-File:        COPYING
+Stability:           experimental
+build-type:          Simple
+
+Package-Url:         http://code.haskell.org/~conal/code/functor-combo
+-- Wait until Cabal 1.6 is more wide-spread and then add the following
+-- in place of the Package-Url field and bump Cabal-Version to >= 1.6.
+-- 
+-- Source-Repository head
+--     type:         darcs
+--     location:     http://code.haskell.org/~conal/code/functor-combo
+
+Library
+  hs-Source-Dirs:      src
+  Extensions:
+  Build-Depends:       base<5, TypeCompose >= 0.8, containers, data-inttrie
+  Exposed-Modules:     
+                       FunctorCombo.Functor
+                       FunctorCombo.Derivative
+                       FunctorCombo.Holey
+                       FunctorCombo.DHoley
+                       FunctorCombo.FixC
+                       FunctorCombo.Regular
+                       FunctorCombo.LocT
+                       FunctorCombo.MemoTrie
+  ghc-options:         -Wall
+
+--  ghc-prof-options:    -prof -auto-all 
diff --git a/src/FunctorCombo/DHoley.hs b/src/FunctorCombo/DHoley.hs
new file mode 100644
--- /dev/null
+++ b/src/FunctorCombo/DHoley.hs
@@ -0,0 +1,175 @@
+{-# LANGUAGE TypeFamilies, TypeOperators, TupleSections #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  FunctorCombo.Holey
+-- Copyright   :  (c) Conal Elliott 2010
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- Filling and extracting derivatives (one-hole contexts)
+                                                         
+-- Variation on Holey, integrating 'Der'
+----------------------------------------------------------------------
+
+module FunctorCombo.DHoley (Holey(..)) where
+
+import Control.Arrow (first,second)
+
+import FunctorCombo.Functor
+
+
+{--------------------------------------------------------------------
+    Extraction
+--------------------------------------------------------------------}
+
+-- | Location, i.e., one-hole context and a value for the hole.
+type Loc f a = (Der f a, a)
+
+class Functor f => Holey f where
+  type Der f :: * -> *                  -- ^ Derivative, i.e., one-hole context
+  fill    :: Loc f a -> f a             -- ^ Fill a hole
+  extract :: f a -> f (Loc f a)         -- ^ All extractions
+
+-- The Functor constraint simplifies several signatures below.
+instance Holey (Const z) where
+  type Der (Const z) = Void
+  fill = error "fill for Const z: no Der values"
+  extract (Const z) = Const z
+
+instance Holey Id where
+  type Der Id = Unit
+  fill (Const (), a) = Id a
+  extract (Id a) = Id (Const (), a)
+
+instance (Holey f, Holey g) => Holey (f :+: g) where
+  type Der (f :+: g) = Der f :+: Der g
+  fill (InL df, a) = InL (fill (df, a))
+  fill (InR df, a) = InR (fill (df, a))
+  extract (InL fa) = InL ((fmap.first) InL (extract fa))
+  extract (InR ga) = InR ((fmap.first) InR (extract ga))
+
+{-
+
+InL fa :: (f :+: g) a
+
+fa :: f a
+
+extract fa :: f (Loc f a)
+
+(fmap.first) InL (extract fa) :: f ((Der f :+: Der g) a, a)
+
+(fmap.first) InL (extract fa) :: f ((Der (f :+: g) a), a)
+
+InL ((fmap.first) InL (extract fa)) :: (f :+: g) ((Der (f :+: g) a), a)
+
+-}
+
+
+-- Der (f :*: g) = Der f :*: g  :+:  f :*: Der g
+
+instance (Holey f, Holey g) => Holey (f :*: g) where
+  type Der (f :*: g) = Der f :*: g  :+:  f :*: Der g
+  fill (InL (dfa :*:  ga), a) = fill (dfa, a) :*: ga
+  fill (InR ( fa :*: dga), a) = fa :*: fill (dga, a)
+  extract (fa :*: ga) = (fmap.first) (InL . (:*: ga)) (extract fa) :*:
+                        (fmap.first) (InR . (fa :*:)) (extract ga)
+
+{-
+
+fa :*: ga :: (f :*: g) a
+
+fa :: f a
+
+extract fa :: f (Loc f a)
+
+(fmap.first) (:*: ga) (extract fa) :: f ((Der f :*: g) a, a)
+
+(fmap.first) (InL . (:*: ga)) (extract fa)
+  :: f (((Der f :*: g) :+: (f :*: Der g)) a, a)
+
+(fmap.first) (InL . (:*: ga)) (extract fa) :: f ((Der (f :*: g)) a, a)
+
+(fmap.first) (InR . (fa :*:)) (extract ga) :: g ((Der (f :*: g)) a, a)
+
+
+(fmap.first) (InL . (:*: ga)) (extract fa) :*: (fmap.first) (InR . (fa :*:)) (extract ga)
+  :: (f :*: g) (Der (f :*: g) a, a)
+
+-}
+
+-- type instance Der (g :.  f) = Der g :. f  :*:  Der f
+
+
+lassoc :: (p,(q,r)) -> ((p,q),r)
+lassoc    (p,(q,r)) =  ((p,q),r)
+
+squishP :: Functor f => (a, f b) -> f (a,b)
+squishP (a,fb) = fmap (a,) fb
+
+tweak1 :: Functor f => (dg (fa), f (dfa, a)) -> f ((dg (fa), dfa), a)
+tweak1 = fmap lassoc . squishP
+
+chainRule :: (dg (f a), df a) -> ((dg :. f) :*: df) a
+chainRule (dgfa, dfa) = O dgfa :*: dfa
+
+tweak2 :: Functor f => (dg (f a), f (df a, a)) -> f (((dg :. f) :*: df) a, a)
+tweak2 = (fmap.first) chainRule . tweak1
+
+-- And more specifically,
+-- 
+-- tweak2 :: Functor f => (Der g (f a), f (Loc f a)) -> f (((Der g :. f) :*: Der f) a, a)
+-- tweak2 :: Functor f => (Der g (f a), f (Loc f a)) -> f (Der (g :. f) a, a)
+
+{-
+(dg fa, f (dfa,a))
+
+f (dg fa, (df,a))
+
+f ((dg fa, dfa), a)
+-}
+
+extractGF :: (Holey f, Holey g) =>
+             g (f a) -> g (f (Loc (g :. f) a))
+extractGF = fmap (tweak2 . second extract) . extract
+
+{-
+
+gfa :: g (f a)
+
+extract gfa :: g (Der g (f a), f a)
+
+fmap (second extract) (extract gfa) :: g (Der g (f a), f (Loc f a))
+
+fmap (tweak2 . second extract) (extract gfa) 
+  :: g (f ((Der (g :. f :*: Der f) a), a))
+
+-}
+
+-- Der (g :.  f) = Der g :. f  :*:  Der f
+
+instance (Holey f, Holey g) => Holey (g :. f) where
+  type Der (g :.  f) = Der g :. f  :*:  Der f
+  -- fill (O dgfa :*: dfa) = O . fill dgfa . fill dfa
+  fill (O dgfa :*: dfa, a) = O (fill (dgfa, fill (dfa, a)))
+  -- extract (O gfa) = O (extractGF gfa)
+  extract = inO extractGF
+
+
+{-
+O dgfa :*: dfa :: Der (g :. f) a
+
+O dgfa :*: dfa :: (Der g :. f :*: Der f) a
+
+dgfa :: Der g (f a)
+dfa  :: Der f a
+
+fill dfa a :: f a
+
+fill dgfa (fill dfa a) :: g (f a)
+
+O (fill dgfa (fill dfa a)) :: (g :. f) a
+
+-}
diff --git a/src/FunctorCombo/Derivative.hs b/src/FunctorCombo/Derivative.hs
new file mode 100644
--- /dev/null
+++ b/src/FunctorCombo/Derivative.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE TypeFamilies, TypeOperators #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  FunctorCombo.Derivative
+-- Copyright   :  (c) Conal Elliott 2010
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- Derivatives (one-hole contexts) for standard Functor combinators
+----------------------------------------------------------------------
+
+module FunctorCombo.Derivative (Der) where
+
+import FunctorCombo.Functor
+
+{--------------------------------------------------------------------
+    Derivatives, i.e., one-hole contexts
+--------------------------------------------------------------------}
+
+-- | A derivative, i.e., a one-hole context for a container f (probably a functor).
+type family Der (f :: (* -> *)) :: (* -> *)
+
+type instance Der (Const a) = Void
+
+type instance Der Id = Unit
+
+type instance Der (f :+: g) = Der f :+: Der g
+
+type instance Der (f :*: g) = Der f :*: g  :+:  f :*: Der g
+
+type instance Der (g :.  f) = Der g :. f  :*:  Der f
+
diff --git a/src/FunctorCombo/FixC.hs b/src/FunctorCombo/FixC.hs
new file mode 100644
--- /dev/null
+++ b/src/FunctorCombo/FixC.hs
@@ -0,0 +1,97 @@
+-- {-# LANGUAGE #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  FunctorCombo.FixC
+-- Copyright   :  (c) Conal Elliott 2010
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- Zippers for functor fixpoints
+----------------------------------------------------------------------
+
+module FunctorCombo.FixC (FixC,LocFix, up,down) where
+
+-- import FunctorCombo.Derivative
+-- import FunctorCombo.Holey
+
+import FunctorCombo.DHoley
+
+
+
+newtype Fix f = Fix { unFix :: f (Fix f) }
+
+-- If Haskell had recursive type synonyms:
+-- 
+--   Fix f =~ f (Fix f)
+
+
+-- | Context for functor fixpoints
+
+-- data FixC f = FixC (Der f (Fix f)) (FixC f)
+
+-- type FixC f = Stream (Der f (Fix f))
+
+-- Or, if we want topped data types:
+
+-- data FixC f = TopC | FixC (Der f (Fix f)) (FixC f)
+
+-- Isomorphically:
+
+type FixC f = [Der f (Fix f)]
+
+-- Reminder:
+-- 
+--   type Loc f a = (Der f a, a)
+
+-- Instead,
+
+type LocFix f = (FixC f, Fix f)
+
+-- TODO: can I relate FixC to Der (Fix f) and use Loc for LocFix?
+
+up :: Holey f => LocFix f -> LocFix f
+up ([],_) = error "up: already at top"
+up (d:ds', t) = (ds', Fix (fill (d,t)))
+
+{-
+
+(d:ds', t) :: LocFix f
+(d:ds', t) :: (FixC f, Fix f)
+
+d:ds' :: [Der f (Fix f)]
+
+t :: Fix f
+
+d   ::  Der f (Fix f)
+ds' :: [Der f (Fix f)]
+
+fill :: Loc f b -> f b
+
+fill (d,t) :: f (Fix f)
+
+Fix (fill (d,t)) :: Fix f
+
+-}
+
+down :: Holey f => LocFix f -> f (LocFix f)
+down (ds', t) = fmap (\ (d,t') -> (d:ds',t')) (extract (unFix t))
+
+{-
+(ds',t) :: LocFix f
+(ds',t) :: (FixC f, Fix f)
+(ds',t) :: ([Der f (Fix f)], Fix f)
+
+ds' :: [Der f (Fix f)]
+t :: Fix f
+unFix t :: f (Fix f)
+
+extract (unFix t) :: f (Der f (Fix f), Fix f)
+
+fmap (\ (d,t') -> (d:ds',t')) (extract (unFix t))
+  :: ([Der f (Fix f)], Fix f)
+  :: (FixC f, Fix f)
+  :: LocFix f
+-}
diff --git a/src/FunctorCombo/Functor.hs b/src/FunctorCombo/Functor.hs
new file mode 100644
--- /dev/null
+++ b/src/FunctorCombo/Functor.hs
@@ -0,0 +1,112 @@
+{-# LANGUAGE TypeOperators, EmptyDataDecls, StandaloneDeriving #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  FunctorCombo.Functor
+-- Copyright   :  (c) Conal Elliott 2010
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- Standard building blocks for functors
+----------------------------------------------------------------------
+
+module FunctorCombo.Functor
+  (
+    Const(..),Void,Unit,Id(..),unId,inId,inId2,(:+:)(..),eitherF
+  , (:*:)(..),(:.)(..),unO,inO,inO2,(~>)
+  ) where
+
+
+import Control.Applicative (Applicative(..),Const(..))
+
+import Control.Compose (Id(..),unId,inId,inId2,(:.)(..),unO,inO,inO2,(~>))
+
+
+-- infixl 9 :.
+infixl 7 :*:
+infixl 6 :+:
+
+
+{--------------------------------------------------------------------
+    Generic functor constructors
+--------------------------------------------------------------------}
+
+-- | Empty/zero type constructor (no inhabitants)
+data Void a
+
+-- | Unit type constructor (one inhabitant)
+type Unit = Const ()
+
+-- From Control.Compose:
+-- 
+--   data Id a = Id a
+
+-- | Product on unary type constructors
+data (f :*: g) a = f a :*: g a deriving (Show)
+
+-- | Sum on unary type constructors
+data (f :+: g) a = InL (f a) | InR (g a) deriving (Show)
+
+eitherF :: (f a -> b) -> (g a -> b) -> (f :+: g) a -> b
+eitherF p _ (InL fa) = p fa
+eitherF _ q (InR ga) = q ga
+
+-- From Control.Compose:
+-- 
+--   newtype (g :. f) a = O (g (f a))
+
+
+{--------------------------------------------------------------------
+    Functor and Applicative instances for generic constructors
+--------------------------------------------------------------------}
+
+instance Functor Void where
+  fmap _ = error "Void fmap: no void value"  -- so ghc won't complain
+
+-- instance Functor Id where
+--   fmap h (Id a) = Id (h a)
+
+-- deriving instance Functor Id
+
+-- instance (Functor f, Functor g) => Functor (f :+: g) where
+--   fmap h (InL fa) = InL (fmap h fa)
+--   fmap h (InR ga) = InR (fmap h ga)
+
+-- i.e.,
+-- 
+--     fmap h . InL  ==  InL . fmap h
+--     fmap h . InR  ==  InR . fmap h
+
+deriving instance (Functor f, Functor g) => Functor (f :+: g)
+
+-- instance (Functor f, Functor g) => Functor (f :*: g) where
+--   fmap h (fa :*: ga) = fmap h fa :*: fmap h ga
+
+-- Or:
+deriving instance (Functor f, Functor g) => Functor (f :*: g)
+
+-- TODO: Verify that the deriving instances are equivalent to the explicit versions.
+
+-- What about Applicative instances?  I think Void could implement (<*>)
+-- but not pure.  Hm.  Id and (:*:) are easy, while (:+:) is problematic.
+
+-- instance Applicative Id where
+--   pure a = Id a
+--   Id f <*> Id x = Id (f x)
+
+-- instance Applicative Id where
+--   pure  = Id
+--   (<*>) = inId2 ($)
+
+instance (Applicative f, Applicative g) => Applicative (f :*: g) where
+  pure a = pure a :*: pure a
+  (f :*: g) <*> (a :*: b) = (f <*> a) :*: (g <*> b)
+
+-- instance (Functor g, Functor f) => Functor (g :. f) where
+--   fmap = inO.fmap.fmap
+
+-- or
+
+-- deriving instance (Functor g, Functor f) => Functor (g :. f)
diff --git a/src/FunctorCombo/Holey.hs b/src/FunctorCombo/Holey.hs
new file mode 100644
--- /dev/null
+++ b/src/FunctorCombo/Holey.hs
@@ -0,0 +1,170 @@
+{-# LANGUAGE TypeFamilies, TypeOperators, TupleSections #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  FunctorCombo.Holey
+-- Copyright   :  (c) Conal Elliott 2010
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- Filling and extracting derivatives (one-hole contexts)
+----------------------------------------------------------------------
+
+module FunctorCombo.Holey (Loc,Holey(..)) where
+
+import Control.Arrow (first,second)
+
+import FunctorCombo.Functor
+import FunctorCombo.Derivative
+
+
+{--------------------------------------------------------------------
+    Extraction
+--------------------------------------------------------------------}
+
+-- | Location, i.e., one-hole context and a value for the hole.
+type Loc f a = (Der f a, a)
+
+-- | Filling and creating one-hole contexts
+class Functor f => Holey f where
+  fill    :: Loc f a -> f a             -- ^ Fill a hole
+  extract :: f a -> f (Loc f a)         -- ^ All extractions
+
+-- The Functor constraint simplifies several signatures below.
+
+instance Holey (Const z) where
+  fill = error "fill for Const z: no Der values"
+  extract (Const z) = Const z
+
+instance Holey Id where
+  fill (Const (), a) = Id a
+  extract (Id a) = Id (Const (), a)
+
+instance (Holey f, Holey g) => Holey (f :+: g) where
+  fill (InL df, a) = InL (fill (df, a))
+  fill (InR df, a) = InR (fill (df, a))
+  extract (InL fa) = InL ((fmap.first) InL (extract fa))
+  extract (InR ga) = InR ((fmap.first) InR (extract ga))
+
+{-
+
+InL fa :: (f :+: g) a
+
+fa :: f a
+
+extract fa :: f (Loc f a)
+
+(fmap.first) InL (extract fa) :: f ((Der f :+: Der g) a, a)
+
+(fmap.first) InL (extract fa) :: f ((Der (f :+: g) a), a)
+
+InL ((fmap.first) InL (extract fa)) :: (f :+: g) ((Der (f :+: g) a), a)
+
+-}
+
+
+-- Der (f :*: g) = Der f :*: g  :+:  f :*: Der g
+
+instance (Holey f, Holey g) => Holey (f :*: g) where
+  fill (InL (dfa :*:  ga), a) = fill (dfa, a) :*: ga
+  fill (InR ( fa :*: dga), a) = fa :*: fill (dga, a)
+  extract (fa :*: ga) = (fmap.first) (InL . (:*: ga)) (extract fa) :*:
+                        (fmap.first) (InR . (fa :*:)) (extract ga)
+
+{-
+
+fa :*: ga :: (f :*: g) a
+
+fa :: f a
+
+extract fa :: f (Loc f a)
+
+(fmap.first) (:*: ga) (extract fa) :: f ((Der f :*: g) a, a)
+
+(fmap.first) (InL . (:*: ga)) (extract fa)
+  :: f (((Der f :*: g) :+: (f :*: Der g)) a, a)
+
+(fmap.first) (InL . (:*: ga)) (extract fa) :: f ((Der (f :*: g)) a, a)
+
+(fmap.first) (InR . (fa :*:)) (extract ga) :: g ((Der (f :*: g)) a, a)
+
+
+(fmap.first) (InL . (:*: ga)) (extract fa) :*: (fmap.first) (InR . (fa :*:)) (extract ga)
+  :: (f :*: g) (Der (f :*: g) a, a)
+
+-}
+
+-- type instance Der (g :.  f) = Der g :. f  :*:  Der f
+
+
+lassoc :: (p,(q,r)) -> ((p,q),r)
+lassoc    (p,(q,r)) =  ((p,q),r)
+
+squishP :: Functor f => (a, f b) -> f (a,b)
+squishP (a,fb) = fmap (a,) fb
+
+tweak1 :: Functor f => (dg (fa), f (dfa, a)) -> f ((dg (fa), dfa), a)
+tweak1 = fmap lassoc . squishP
+
+chainRule :: (dg (f a), df a) -> ((dg :. f) :*: df) a
+chainRule (dgfa, dfa) = O dgfa :*: dfa
+
+tweak2 :: Functor f => (dg (f a), f (df a, a)) -> f (((dg :. f) :*: df) a, a)
+tweak2 = (fmap.first) chainRule . tweak1
+
+-- And more specifically,
+-- 
+-- tweak2 :: Functor f => (Der g (f a), f (Loc f a)) -> f (((Der g :. f) :*: Der f) a, a)
+-- tweak2 :: Functor f => (Der g (f a), f (Loc f a)) -> f (Der (g :. f) a, a)
+
+{-
+(dg fa, f (dfa,a))
+
+f (dg fa, (df,a))
+
+f ((dg fa, dfa), a)
+-}
+
+extractGF :: (Holey f, Holey g) =>
+             g (f a) -> g (f (Loc (g :. f) a))
+extractGF = fmap (tweak2 . second extract) . extract
+
+{-
+
+gfa :: g (f a)
+
+extract gfa :: g (Der g (f a), f a)
+
+fmap (second extract) (extract gfa) :: g (Der g (f a), f (Loc f a))
+
+fmap (tweak2 . second extract) (extract gfa) 
+  :: g (f ((Der (g :. f :*: Der f) a), a))
+
+-}
+
+-- Der (g :.  f) = Der g :. f  :*:  Der f
+
+instance (Holey f, Holey g) => Holey (g :. f) where
+  -- fill (O dgfa :*: dfa) = O . fill dgfa . fill dfa
+  fill (O dgfa :*: dfa, a) = O (fill (dgfa, fill (dfa, a)))
+  -- extract (O gfa) = O (extractGF gfa)
+  extract = inO extractGF
+
+
+{-
+O dgfa :*: dfa :: Der (g :. f) a
+
+O dgfa :*: dfa :: (Der g :. f :*: Der f) a
+
+dgfa :: Der g (f a)
+dfa  :: Der f a
+
+fill dfa a :: f a
+
+fill dgfa (fill dfa a) :: g (f a)
+
+O (fill dgfa (fill dfa a)) :: (g :. f) a
+
+-}
diff --git a/src/FunctorCombo/LocT.hs b/src/FunctorCombo/LocT.hs
new file mode 100644
--- /dev/null
+++ b/src/FunctorCombo/LocT.hs
@@ -0,0 +1,73 @@
+{-# LANGUAGE TypeFamilies, TypeOperators, FlexibleContexts #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  FunctorCombo.LocT
+-- Copyright   :  (c) Conal Elliott 2010
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- 
+----------------------------------------------------------------------
+
+module FunctorCombo.LocT
+  (
+    Context,LocT, up, down
+  ) where
+
+
+-- import FunctorCombo.Derivative
+-- import FunctorCombo.Holey
+
+import FunctorCombo.DHoley
+
+import FunctorCombo.Regular
+
+-- TODO: Bring in pattern functors (as in PolyP), so I don't have to
+-- work on fixpoints directly.  Something like
+-- 
+--   type Context t = [Der (PF t) t]
+-- 
+--   type LocT t = (Context t, t)
+-- 
+-- Then use with some standard recursive data types like lists & trees.
+
+-- TODO: Consider the implications of my style of zipper, using f (Der
+-- ...), contrasted with the traditional one.  Try an application of mine
+-- to make sure it's useful.  And that I avoid staring into the void.
+
+-- TODO: rename wrap/unwrap, e.g., to reg/unreg
+
+type Context t = [Der (PF t) t]
+
+type LocT t = (Context t, t)
+
+up :: (Regular t, Holey (PF t)) => LocT t -> LocT t
+up ([],_) = error "up: already at top"
+up (d:ds', t) = (ds', wrap (fill (d,t)))
+
+
+down :: (Regular t, Holey (PF t)) => LocT t -> PF t (LocT t)
+down (ds', t) = fmap (\ (d,t') -> (d:ds',t')) (extract (unwrap t))
+
+{-
+
+type P = Id :*: Id                      -- pairs
+type Q = P  :*: P                       -- quadruples (or P :. P)
+
+type Two  a = (a,a)
+
+type Four a = Two (Two a)
+
+data QuadTree a = QuadTree a (Four (QuadTree a))
+
+instance Regular (QuadTree a) where
+  type PF (QuadTree a) = Const a :*: Q
+  unwrap (QuadTree a ((p,q),(r,s))) =
+    Const a :*: ((Id p :*: Id q) :*: (Id r :*: Id s))
+  wrap (Const a :*: ((Id p :*: Id q) :*: (Id r :*: Id s))) =
+    QuadTree a ((p,q),(r,s))
+
+-}
diff --git a/src/FunctorCombo/MemoTrie.hs b/src/FunctorCombo/MemoTrie.hs
new file mode 100644
--- /dev/null
+++ b/src/FunctorCombo/MemoTrie.hs
@@ -0,0 +1,312 @@
+{-# LANGUAGE TypeOperators, TypeFamilies, UndecidableInstances, CPP
+ #-}
+{-# OPTIONS_GHC -Wall #-}
+{-# OPTIONS_GHC -fno-warn-unused-binds #-}  -- temporary while testing
+----------------------------------------------------------------------
+-- |
+-- Module      :  FunctorCombo.MemoTrie
+-- Copyright   :  (c) Conal Elliott 2010
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- Functor-based memo tries (strict for now)
+-- 
+-- Warning: this formulation cannot handle recursive types.
+-- The type checker fails to terminate.  Wondering about solutions.
+----------------------------------------------------------------------
+
+module FunctorCombo.MemoTrie
+  (
+    HasTrie(..),memo,memo2,memo3
+  ) where
+
+import Control.Arrow (first)
+import Control.Applicative ((<$>))
+
+import qualified Data.IntTrie as IT  -- data-inttrie
+import Data.Tree
+
+import Control.Compose (result)
+
+import FunctorCombo.Functor
+import FunctorCombo.Regular
+
+
+{--------------------------------------------------------------------
+    Class
+--------------------------------------------------------------------}
+
+infixr 0 :->:
+
+-- | Memo trie from k to v
+type k :->: v = Trie k v
+
+-- | Domain types with associated memo tries
+class HasTrie k where
+    -- | Representation of trie with domain type @a@
+    type Trie k :: * -> *
+    -- | Create the trie for the entire domain of a function
+    trie   :: (k  ->  v) -> (k :->: v)
+    -- | Convert k trie to k function, i.e., access k field of the trie
+    untrie :: (k :->: v) -> (k  ->  v)
+    -- | List the trie elements.  Order of keys (@:: k@) is always the same.
+    enumerate :: (k :->: v) -> [(k,v)]
+
+-- -- | Domain elements of a trie
+-- domain :: HasTrie a => [a]
+-- domain = map fst (enumerate (trie (const oops)))
+--  where
+--    oops = error "Data.MemoTrie.domain: range element evaluated."
+
+
+{--------------------------------------------------------------------
+    Memo functions
+--------------------------------------------------------------------}
+
+-- | Trie-based function memoizer
+memo :: HasTrie k => Unop (k -> v)
+memo = untrie . trie
+
+-- | Memoize a binary function, on its first argument and then on its
+-- second.  Take care to exploit any partial evaluation.
+memo2 :: (HasTrie s,HasTrie t) => Unop (s -> t -> a)
+
+-- | Memoize a ternary function on successive arguments.  Take care to
+-- exploit any partial evaluation.
+memo3 :: (HasTrie r,HasTrie s,HasTrie t) => Unop (r -> s -> t -> a)
+
+-- | Lift a memoizer to work with one more argument.
+mup :: HasTrie t => (b -> c) -> (t -> b) -> (t -> c)
+mup mem f = memo (mem . f)
+
+memo2 = mup memo
+memo3 = mup memo2
+
+{--------------------------------------------------------------------
+    Instances
+--------------------------------------------------------------------}
+
+instance HasTrie () where
+  type Trie ()  = Id
+  trie   f      = Id (f ())
+  untrie (Id v) = const v
+  enumerate (Id a) = [((),a)]
+
+instance (HasTrie a, HasTrie b) => HasTrie (Either a b) where
+  type Trie (Either a b) = Trie a :*: Trie b
+  trie   f           = trie (f . Left) :*: trie (f . Right)
+  untrie (ta :*: tb) = untrie ta `either` untrie tb
+  enumerate (ta :*: tb) = enum' Left ta `weave` enum' Right tb
+
+enum' :: (HasTrie a) => (a -> a') -> (a :->: b) -> [(a', b)]
+enum' f = (fmap.first) f . enumerate
+
+weave :: [a] -> [a] -> [a]
+[] `weave` as = as
+as `weave` [] = as
+(a:as) `weave` bs = a : (bs `weave` as)
+
+
+instance (HasTrie a, HasTrie b) => HasTrie (a , b) where
+  type Trie (a , b) = Trie a :. Trie b
+  trie   f = O (trie (trie . curry f))
+  untrie (O tt) = uncurry (untrie . untrie tt)
+  enumerate (O tt) =
+    [ ((a,b),x) | (a,t) <- enumerate tt , (b,x) <- enumerate t ]
+
+-- Experiment:
+
+#define HasTrieIsomorph(Context,Type,IsoType,toIso,fromIso) \
+instance Context => HasTrie (Type) where {\
+  type Trie (Type) = Trie (IsoType); \
+  trie f = trie (f . (fromIso)); \
+  untrie t = untrie t . (toIso); \
+  enumerate = (result.fmap.first) (fromIso) enumerate; \
+}
+
+
+HasTrieIsomorph( (), Bool, Either () ()
+               , bool (Left ()) (Right ())
+               , either (\ () -> True) (\ () -> False))
+
+HasTrieIsomorph((HasTrie a, HasTrie b, HasTrie c), (a,b,c), ((a,b),c)
+               , \ (a,b,c) -> ((a,b),c), \ ((a,b),c) -> (a,b,c))
+
+HasTrieIsomorph((HasTrie a, HasTrie b, HasTrie c, HasTrie d)
+               , (a,b,c,d), ((a,b,c),d)
+               , \ (a,b,c,d) -> ((a,b,c),d), \ ((a,b,c),d) -> (a,b,c,d))
+
+
+-- As well as the functor combinators themselves
+
+HasTrieIsomorph( HasTrie x, Const x a, x, getConst, Const )
+
+HasTrieIsomorph( HasTrie a, Id a, a, unId, Id )
+
+HasTrieIsomorph( (HasTrie (f a), HasTrie (g a))
+               , (f :*: g) a, (f a,g a)
+               , \ (fa :*: ga) -> (fa,ga), \ (fa,ga) -> (fa :*: ga) )
+
+HasTrieIsomorph( (HasTrie (f a), HasTrie (g a))
+               , (f :+: g) a, Either (f a) (g a)
+               , eitherF Left Right, either InL InR )
+
+HasTrieIsomorph( HasTrie (g (f a))
+               , (g :. f) a, g (f a) , unO, O )
+
+
+
+
+-- #define HasTrieRegular(Context,Type) \
+-- HasTrieIsomorph(Context, Type, PF (Type) (Type) , unwrap, wrap)
+
+-- #define HasTrieRegular1(TypeCon) \
+-- HasTrieRegular(HasTrie a, TypeCon a)
+
+-- Hangs ghc 6.12.1:
+-- 
+-- HasTrieRegular(HasTrie a, [a])
+-- HasTrieRegular(HasTrie a, Tree a)
+
+-- HasTrieRegular1([])
+-- HasTrieRegular1(Tree)
+
+-- I think the problem is infinite types.  Try an explicit newtype to
+-- break the cycle.
+
+
+-- newtype ListTrie a v = ListTrie (PF [a] [a] :->: v)
+ 
+-- instance HasTrie a => HasTrie [a] where
+--   type Trie [a] = ListTrie a
+--   trie f = ListTrie (trie (f . wrap))
+--   untrie (ListTrie t) = untrie t . unwrap
+--   enumerate (ListTrie t) = (result.fmap.first) wrap enumerate $ t
+
+-- Works.  Now abstract into a macro
+
+#define HasTrieRegular(Context,Type,TrieType,TrieCon) \
+newtype TrieType v = TrieCon (PF (Type) (Type) :->: v); \
+instance Context => HasTrie (Type) where { \
+  type Trie (Type) = TrieType; \
+  trie f = TrieCon (trie (f . wrap)); \
+  untrie (TrieCon t) = untrie t . unwrap; \
+  enumerate (TrieCon t) = (result.fmap.first) wrap enumerate t; \
+}; \
+HasTrieIsomorph( HasTrie (PF (Type) (Type) :->: v) \
+               , TrieType v, PF (Type) (Type) :->: v \
+               , \ (TrieCon w) -> w, TrieCon )
+
+-- For instance,
+
+-- HasTrieRegular(HasTrie a, [a] , ListTrie a, ListTrie)
+-- HasTrieRegular(HasTrie a, Tree, TreeTrie a, TreeTrie)
+
+-- Simplify a bit with a macro for unary regular types.
+-- Make similar defs for binary etc as needed.
+
+#define HasTrieRegular1(TypeCon,TrieCon) \
+HasTrieRegular(HasTrie a, TypeCon a, TrieCon a, TrieCon)
+
+HasTrieRegular1([]  , ListTrie)
+HasTrieRegular1(Tree, TreeTrie)
+
+-- HasTrieIsomorph(Context,Type,IsoType,toIso,fromIso)
+
+-- HasTrieIsomorph( HasTrie (PF [a] [a] :->: v)
+--                , ListTrie a v, PF [a] [a] :->: v
+--                , \ (ListTrie w) -> w, ListTrie )
+
+
+
+
+
+enumerateEnum :: (Enum k, Num k, HasTrie k) => (k :->: v) -> [(k,v)]
+enumerateEnum t = [(k, f k) | k <- [0 ..] `weave` [-1, -2 ..]]
+ where
+   f = untrie t
+
+#define HasTrieIntegral(Type) \
+instance HasTrie Type where { \
+  type Trie Type = IT.IntTrie; \
+  trie   = (<$> IT.identity); \
+  untrie = IT.apply; \
+  enumerate = enumerateEnum; \
+}
+
+HasTrieIntegral(Int)
+HasTrieIntegral(Integer)
+
+
+-- Memoizing higher-order functions
+
+HasTrieIsomorph((HasTrie a, HasTrie (a :->: b)), a -> b, a :->: b, trie, untrie)
+
+
+{--------------------------------------------------------------------
+    Misc
+--------------------------------------------------------------------}
+
+type Unop a = a -> a
+
+bool :: a -> a -> Bool -> a
+bool t e b = if b then t else e
+
+{-
+
+{--------------------------------------------------------------------
+    Testing
+--------------------------------------------------------------------}
+
+fib :: Integer -> Integer
+fib m = mfib m
+ where
+   mfib = memo fib'
+   fib' 0 = 0
+   fib' 1 = 1
+   fib' n = mfib (n-1) + mfib (n-2)
+
+-- The eta-redex in fib is important to prevent a CAF.
+
+
+-}
+
+{-
+
+ft1 :: (Bool -> a) -> (a,a)
+ft1 f = (f False, f True)
+
+f1 :: Bool -> Int
+f1 False = 0
+f1 True  = 1
+
+trie1a :: (Bool -> Int) :->: (Int, Int)
+trie1a = trie ft1
+
+trie1b :: (Bool :->: Int) :->: (Int, Int)
+trie1b = trie1a
+
+trie1c :: (Either () () :->: Int) :->: (Int, Int)
+trie1c = trie1a
+
+trie1d :: ((Trie () :*: Trie ()) Int) :->: (Int, Int)
+trie1d = trie1a
+
+trie1e :: (Trie () Int, Trie () Int) :->: (Int, Int)
+trie1e = trie1a
+
+trie1f :: (() :->: Int, () :->: Int) :->: (Int, Int)
+trie1f = trie1a
+
+trie1g :: (Int, Int) :->: (Int, Int)
+trie1g = trie1a
+
+trie1h :: (Trie Int :. Trie Int) (Int, Int)
+trie1h = trie1a
+
+trie1i :: Int :->: Int :->: (Int, Int)
+trie1i = unO trie1a
+
+-}
diff --git a/src/FunctorCombo/Regular.hs b/src/FunctorCombo/Regular.hs
new file mode 100644
--- /dev/null
+++ b/src/FunctorCombo/Regular.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE TypeFamilies, TypeOperators, FlexibleContexts #-}
+{-# OPTIONS_GHC -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      :  FunctorCombo.Regular
+-- Copyright   :  (c) Conal Elliott 2010
+-- License     :  BSD3
+-- 
+-- Maintainer  :  conal@conal.net
+-- Stability   :  experimental
+-- 
+-- Regular data types
+----------------------------------------------------------------------
+
+module FunctorCombo.Regular (Regular(..)) where
+
+import Data.Tree
+
+import FunctorCombo.Functor
+
+
+-- Pattern functors, similar to PolyC and the Regular class from
+-- UU (e.g., "A Lightweight Approach to Datatype-Generic Rewriting")
+
+class Functor (PF t) => Regular t where
+  type PF t :: * -> *
+  wrap   :: PF t t -> t
+  unwrap :: t -> PF t t
+
+
+-- Some Regular instances:
+
+instance Regular [a] where
+  type PF [a] = Unit :+: Const a :*: Id
+  unwrap []     = InL (Const ())
+  unwrap (a:as) = InR (Const a :*: Id as)
+  wrap (InL (Const ()))          = []
+  wrap (InR (Const a :*: Id as)) = a:as
+
+
+-- Rose tree (from Data.Tree)
+-- 
+--   data Tree  a = Node a [Tree a]
+
+-- instance Functor Tree where
+--   fmap f (Node a ts) = Node (f a) (fmap f ts)
+
+instance Regular (Tree a) where
+  type PF (Tree a) = Const a :*: []
+  unwrap (Node a ts) = Const a :*: ts
+  wrap (Const a :*: ts) = Node a ts
