diff --git a/src/Data/Cross.hs b/src/Data/Cross.hs
--- a/src/Data/Cross.hs
+++ b/src/Data/Cross.hs
@@ -48,8 +48,7 @@
 instance AdditiveGroup u => HasCross2 (u,u) where
   cross2 (x,y) = (negateV y,x)  -- or @(y,-x)@?
 
-instance ( HasBasis a, HasTrie (Basis a)
-         , VectorSpace v, HasCross2 v) => HasCross2 (a:>v) where
+instance (HasTrie (Basis a), HasCross2 v) => HasCross2 (a:>v) where
   -- 2d cross-product is linear
   cross2 = fmapD cross2
 
@@ -73,8 +72,7 @@
 -- l `atB` b = maybe zeroV (`untrie` b) l
 
 
-instance ( Num s, VectorSpace s
-         , HasBasis s, HasTrie (Basis s), Basis s ~ ())
+instance (VectorSpace s, HasBasis s, HasTrie (Basis s), Basis s ~ ())
     => HasNormal (Two (One s :> s)) where
   normalVec = unpairD . normalVec . pairD
 
@@ -101,7 +99,7 @@
    where
      d = derivAtBasis v
 
-instance ( Num s, VectorSpace s, HasBasis s, HasTrie (Basis s)
-         , HasNormal (Two s :> Three s))
+instance ( VectorSpace s, HasBasis s, HasTrie (Basis s)
+         , HasNormal (Two s :> Three s) )
          => HasNormal (Three (Two s :> s)) where
   normalVec = untripleD . normalVec . tripleD
diff --git a/src/Data/LinearMap.hs b/src/Data/LinearMap.hs
--- a/src/Data/LinearMap.hs
+++ b/src/Data/LinearMap.hs
@@ -1,10 +1,11 @@
+{-# LANGUAGE TupleSections #-}
 {-# LANGUAGE CPP, TypeOperators, FlexibleContexts, TypeFamilies
   , GeneralizedNewtypeDeriving, StandaloneDeriving, UndecidableInstances #-}
 {-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
 ----------------------------------------------------------------------
 -- |
 -- Module      :  Data.LinearMap
--- Copyright   :  (c) Conal Elliott 2008-2012
+-- Copyright   :  (c) Conal Elliott 2008-2016
 -- License     :  BSD3
 --
 -- Maintainer  :  conal@conal.net
@@ -18,7 +19,8 @@
    , inLMap, inLMap2, inLMap3
    , liftMS, liftMS2, liftMS3
    , liftL, liftL2, liftL3
-   , firstL
+   , exlL, exrL, forkL, firstL, secondL
+   , inlL, inrL, joinL -- , leftL, rightL
    )
   where
 
@@ -26,7 +28,7 @@
 import Control.Applicative (Applicative)
 #endif
 import Control.Applicative (liftA2, liftA3)
-import Control.Arrow       (first)
+import Control.Arrow       (first,second)
 
 import Data.MemoTrie      (HasTrie(..),(:->:))
 import Data.AdditiveGroup (Sum(..), AdditiveGroup(..))
@@ -45,6 +47,7 @@
 
 type LMap' u v = MSum (Basis u :->: v)
 
+infixr 1 :-*
 -- | Linear map, represented as an optional memo-trie from basis to
 -- values, where 'Nothing' means the zero map (an optimization).
 newtype u :-* v = LMap { unLMap :: LMap' u v }
@@ -61,13 +64,34 @@
 -- in the constraint: HasTrie (Basis u)
 -- (Use UndecidableInstances to permit this)
 
-firstL :: ( HasBasis u, HasBasis u', HasBasis v
-          , HasTrie (Basis u), HasTrie (Basis v) 
-          , Scalar u ~ Scalar v, Scalar u ~ Scalar u'
-          ) =>
-          (u :-* u') -> ((u,v) :-* (u',v))
-firstL = linear.first.lapply
+exlL :: ( HasBasis a, HasTrie (Basis a), HasBasis b, HasTrie (Basis b)
+        , Scalar a ~ Scalar b )
+     => (a,b) :-* a
+exlL = linear fst
 
+exrL :: ( HasBasis a, HasTrie (Basis a), HasBasis b, HasTrie (Basis b)
+        , Scalar a ~ Scalar b )
+     => (a,b) :-* b
+exrL = linear snd
+
+forkL :: (HasTrie (Basis a), HasBasis c, HasBasis d)
+      => (a :-* c) -> (a :-* d) -> (a :-* (c,d))
+forkL = (inLMap2.liftL2) (,)
+
+firstL  :: ( HasBasis u, HasBasis u', HasBasis v
+           , HasTrie (Basis u), HasTrie (Basis v) 
+           , Scalar u ~ Scalar v, Scalar u ~ Scalar u'
+           ) =>
+           (u :-* u') -> ((u,v) :-* (u',v))
+firstL  = linear.first.lapply
+
+secondL :: ( HasBasis u, HasBasis v, HasBasis v'
+           , HasTrie (Basis u), HasTrie (Basis v) 
+           , Scalar u ~ Scalar v, Scalar u ~ Scalar v'
+           ) =>
+           (v :-* v') -> ((u,v) :-* (u,v'))
+secondL = linear.second.lapply
+
 -- TODO: more efficient firstL
 
 -- liftMS :: (AdditiveGroup a) => (a -> b) -> (MSum a -> MSum b)
@@ -78,6 +102,21 @@
 -- (inLMap.liftMS.fmap) (s *^) :: (u :-* v) -> (u :-* v)
 
 
+inlL :: (HasBasis a, HasTrie (Basis a), HasBasis b)
+     => a :-* (a,b)
+inlL = linear (,zeroV)
+
+inrL :: (HasBasis a, HasBasis b, HasTrie (Basis b))
+     => b :-* (a,b)
+inrL = linear (zeroV,)
+
+joinL :: ( HasBasis a, HasTrie (Basis a)
+         , HasBasis b, HasTrie (Basis b)
+         , Scalar a ~ Scalar b, Scalar a ~ Scalar c
+         , VectorSpace c )
+      => (a :-* c) -> (b :-* c) -> ((a,b) :-* c)
+f `joinL` g = linear (\ (a,b) -> lapply f a ^+^ lapply g b)
+
 -- Before version 0.7, u :-* v was a type synonym, resulting in a subtle
 -- ambiguity: u:-*v == u':-*v' does not imply that u==u', since Basis
 -- might map different types to the same basis (e.g., Float & Double).
@@ -137,7 +176,7 @@
 
 infixr 9 *.*
 -- | Compose linear maps
-(*.*) :: ( HasBasis u, HasTrie (Basis u)
+(*.*) :: ( HasTrie (Basis u)
          , HasBasis v, HasTrie (Basis v)
          , VectorSpace w
          , Scalar v ~ Scalar w ) =>
@@ -182,9 +221,7 @@
 -- to values and then decomposed, followed by recombination of the
 -- results.
 
-liftMS :: (AdditiveGroup a) =>
-          (a -> b)
-       -> (MSum a -> MSum b)
+liftMS :: (a -> b) -> (MSum a -> MSum b)
 -- liftMS _ Nothing = Nothing
 -- liftMS h ma = Just (Sum (h (z ma)))
 
@@ -209,8 +246,7 @@
 
 -- | Apply a linear function to each element of a linear map.
 -- @liftL f l == linear f *.* l@, but works more efficiently.
-liftL :: (Functor f, AdditiveGroup (f a)) =>
-         (a -> b) -> MSum (f a) -> MSum (f b)
+liftL :: Functor f => (a -> b) -> MSum (f a) -> MSum (f b)
 liftL = liftMS . fmap
 
 -- | Apply a linear binary function (not to be confused with a bilinear
@@ -261,7 +297,6 @@
 
 
 -}
-
 
 -----
 
diff --git a/src/Data/Maclaurin.hs b/src/Data/Maclaurin.hs
--- a/src/Data/Maclaurin.hs
+++ b/src/Data/Maclaurin.hs
@@ -74,8 +74,7 @@
 
 infixl 4 <$>>
 -- | Map a /linear/ function over a derivative tower.
-fmapD, (<$>>) :: (HasBasis a, HasTrie (Basis a), AdditiveGroup b) =>
-                 (b -> c) -> (a :> b) -> (a :> c)
+fmapD, (<$>>) :: HasTrie (Basis a) => (b -> c) -> (a :> b) -> (a :> c)
 fmapD f = lf
  where
    lf (D b0 b') = D (f b0) ((inLMap.liftL) lf b')
@@ -111,9 +110,7 @@
 
 -- | Differentiable identity function.  Sometimes called "the
 -- derivation variable" or similar, but it's not really a variable.
-idD :: ( VectorSpace u, s ~ Scalar u
-       , VectorSpace (u :> u), VectorSpace s
-       , HasBasis u, HasTrie (Basis u)) =>
+idD :: (VectorSpace u , HasBasis u, HasTrie (Basis u)) =>
        u :~> u
 idD = linearD id
 
@@ -168,9 +165,7 @@
 -- | Derivative tower for applying a binary function that distributes over
 -- addition, such as multiplication.  A bit weaker assumption than
 -- bilinearity.  Is bilinearity necessary for correctness here?
-distrib :: forall a b c u.
-           ( HasBasis a, HasTrie (Basis a)
-           , AdditiveGroup b, AdditiveGroup c, AdditiveGroup u) =>
+distrib :: forall a b c u. (HasBasis a, HasTrie (Basis a) , AdditiveGroup u) =>
            (b -> c -> u) -> (a :> b) -> (a :> c) -> (a :> u)
 
 distrib op = (#)
@@ -190,7 +185,7 @@
 instance Show b => Show (a :> b) where
   show (D b0 _) = "D " ++ show b0  ++ " ..."
 
-instance Eq   b => Eq   (a :> b) where (==)    = noOv "(==)"
+instance Eq   (a :> b) where (==)    = noOv "(==)"
 
 type instance BooleanOf (a :> b) = BooleanOf b
 
@@ -198,8 +193,7 @@
       IfB (u :> v) where
   ifB = liftD2 . ifB
 
-instance (AdditiveGroup v, HasBasis u, HasTrie (Basis u), OrdB v) =>
-         OrdB (u :> v) where
+instance OrdB v => OrdB (u :> v) where
   (<*) = (<*) `on` powVal
 
 instance ( AdditiveGroup b, HasBasis a, HasTrie (Basis a)
@@ -218,8 +212,7 @@
   -- Less efficient: adds zero
   -- (^+^)   = liftD2 (^+^)
 
-instance ( HasBasis a, HasTrie (Basis a)
-         , VectorSpace u, AdditiveGroup (Scalar u) )
+instance (HasBasis a, HasTrie (Basis a), VectorSpace u)
       => VectorSpace (a :> u) where
   type Scalar (a :> u) = (a :> Scalar u)
   (*^) = distrib (*^)                     
@@ -241,8 +234,7 @@
 infix  0 >-<
 
 -- | Specialized chain rule.  See also '(\@.)'
-(>-<) :: ( HasBasis a, HasTrie (Basis a), VectorSpace u
-         , AdditiveGroup (Scalar u)) =>
+(>-<) :: (HasBasis a, HasTrie (Basis a), VectorSpace u) =>
          (u -> u) -> ((a :> u) -> (a :> Scalar u))
       -> (a :> u) -> (a :> u)
 f >-< f' = \ u@(D u0 u') -> D (f u0) ((inLMap.liftMS) (f' u *^) u')
@@ -298,31 +290,21 @@
 
 ---- Misc
 
-pairD :: ( HasBasis a, HasTrie (Basis a)
-         , VectorSpace b, VectorSpace c
-         , Scalar b ~ Scalar c
-         ) => (a:>b,a:>c) -> a:>(b,c)
+pairD :: (HasBasis a, HasTrie (Basis a), VectorSpace b, VectorSpace c)
+      => (a:>b,a:>c) -> a:>(b,c)
 
 pairD (u,v) = liftD2 (,) u v
 
-unpairD :: ( HasBasis a, HasTrie (Basis a)
-           , VectorSpace a, VectorSpace b, VectorSpace c
-           , Scalar b ~ Scalar c
-           ) => (a :> (b,c)) -> (a:>b, a:>c)
+unpairD :: HasTrie (Basis a) => (a :> (b,c)) -> (a:>b, a:>c)
 unpairD d = (fst <$>> d, snd <$>> d)
 
 
 tripleD :: ( HasBasis a, HasTrie (Basis a)
            , VectorSpace b, VectorSpace c, VectorSpace d
-           , Scalar b ~ Scalar c, Scalar c ~ Scalar d
            ) => (a:>b,a:>c,a:>d) -> a:>(b,c,d)
 tripleD (u,v,w) = liftD3 (,,) u v w
 
-untripleD :: ( HasBasis a, HasTrie (Basis a)
-             , VectorSpace a, VectorSpace b, VectorSpace c, VectorSpace d
-             , Scalar b ~ Scalar c, Scalar c ~ Scalar d
-             ) =>
-             (a :> (b,c,d)) -> (a:>b, a:>c, a:>d)
+untripleD :: HasTrie (Basis a) => (a :> (b,c,d)) -> (a:>b, a:>c, a:>d)
 untripleD d =
   ((\ (a,_,_) -> a) <$>> d, (\ (_,b,_) -> b) <$>> d, (\ (_,_,c) -> c) <$>> d)
 
diff --git a/vector-space.cabal b/vector-space.cabal
--- a/vector-space.cabal
+++ b/vector-space.cabal
@@ -1,5 +1,5 @@
 Name:                vector-space
-Version:             0.10.3
+Version:             0.10.4
 Cabal-Version:       >= 1.6
 Synopsis:            Vector & affine spaces, linear maps, and derivatives
 Category:            math
