diff --git a/DeepLearning/ConvNet.hs b/DeepLearning/ConvNet.hs
--- a/DeepLearning/ConvNet.hs
+++ b/DeepLearning/ConvNet.hs
@@ -14,18 +14,28 @@
 -}
 module DeepLearning.ConvNet
     (
-     (>->),
+     -- ** Main Types
+     Vol,
      DVol,
-     Forward,
+     Label,
+
+     -- ** Layers
+     Layer,
      InnerLayer,
-     SoftMaxLayer(..),
      TopLayer,
-     Vol,
+     SoftMaxLayer(..),
+     FullyConnectedLayer(..),
+
+     -- ** Composing layers
+     (>->),
+     Forward,
+     withActivations,
+
+     -- ** Network building helpers
      flowNetwork,
      net1,
      net2,
      newFC,
-     withActivations,
     ) where
 
 import           Control.Monad as CM
@@ -35,9 +45,6 @@
 import qualified Data.Vector.Unboxed                  as V
 import           Prelude                              as P hiding (map, zipWith)
 
-
--- ** Helper Types
-
 -- |Activation matrix
 type Vol sh = Array U sh Double
 -- |Delayed activation matrix
@@ -46,18 +53,24 @@
 -- |Label for supervised learning
 type Label = Int
 
--- **  Top Layers
+-- |'Layer' reprsents a layer that can pass activations forward.
+-- 'TopLayer' and 'InnerLayer' are derived layers that can be
+-- backpropagated through.
+class (Shape sh, Shape sh') => Layer a sh sh' | a -> sh, a -> sh' where
+    forward :: (Monad m) => a -> Vol sh -> m (DVol sh')
+
 -- |'TopLayer' is a top level layer that can initialize a
 -- backpropagation pass.
-class TopLayer a where
-    topForward :: (Monad m) => a -> Vol DIM1 -> m (DVol DIM1)
+class Layer a DIM1 DIM1 => TopLayer a where
     topBackward :: (Monad m) => a -> Label -> Vol DIM1 -> Vol DIM1 -> m (DVol DIM1)
 
 -- |'SoftMaxLayer' computes the softmax activation function.
-data SoftMaxLayer = SoftMaxLayer -- 
+data SoftMaxLayer = SoftMaxLayer --
 
+instance Layer SoftMaxLayer DIM1 DIM1 where
+    forward _ = softMaxForward
+
 instance TopLayer SoftMaxLayer where
-    topForward _ = softMaxForward
     topBackward _ = softMaxBackward
 
 softMaxForward :: (Shape sh, Monad m) => Vol sh -> m (DVol sh)
@@ -80,11 +93,9 @@
               indicator = label == target
               bool2Double x = if x then 1.0 else 0.0
 
--- ** Inner Layers
 -- |'InnerLayer' represents an inner layer of a neural network that
 -- can accept backpropagation input from higher layers
-class (Shape sh, Shape sh') => InnerLayer a sh sh' | a -> sh, a -> sh' where
-    innerForward :: Monad m => a -> Vol sh -> m (DVol sh')
+class (Layer a sh sh', Shape sh, Shape sh') => InnerLayer a sh sh' | a -> sh, a -> sh' where
     innerBackward :: Monad m => a -> Vol sh' -> Vol sh -> m (DVol sh)
 
 -- |'FullyConnectedLayer' represents a fully-connected input layer
@@ -93,8 +104,10 @@
       _bias    :: Vol DIM1
     }
 
+instance (Shape sh) => Layer (FullyConnectedLayer sh) sh DIM1 where
+    forward = fcForward
+
 instance (Shape sh) => InnerLayer (FullyConnectedLayer sh) sh DIM1 where
-    innerForward = fcForward
     innerBackward = fcBackward
 
 fcForward :: (Shape sh, Monad m)
@@ -118,12 +131,10 @@
       prod lv rv = V.sum $ V.zipWith (*) lv rv
 
 
--- ** Composing Layers
-
 -- |The 'Forward' function represents a single forward pass through a layer.
 type Forward m sh sh' = (Vol sh -> WriterT [V.Vector Double] m (DVol sh'))
 
--- |'(>->)' composes two forward activation functions
+-- |'>->' composes two forward activation functions
 (>->) :: (Monad m, Shape sh, Shape sh', Shape sh'')
         => Forward m sh sh' -> Forward m sh' sh'' -> Forward m sh sh''
 (f >-> g) input = do
@@ -137,8 +148,7 @@
 net1
   :: (Monad m, InnerLayer a sh DIM1, TopLayer a1) =>
      a -> a1 -> Forward m sh DIM1
-net1 bottom top = innerForward bottom >-> topForward top
-
+net1 bottom top = forward bottom >-> forward top
 
 -- |'net1' constructs a two-layer fully connected MLP with
 -- softmax output.
@@ -146,7 +156,7 @@
   :: (Monad m, InnerLayer a sh sh', InnerLayer a1 sh' DIM1,
       TopLayer a2) =>
      a -> a1 -> a2 -> Forward m sh DIM1
-net2 bottom middle top = innerForward bottom >-> net1 middle top
+net2 bottom middle top = forward bottom >-> net1 middle top
 
 -- |'withActivations' computes the output activation, along with the
 -- intermediate activations
@@ -177,9 +187,11 @@
 flowNetwork :: (Monad m, Shape sh) => sh -> Int -> Int -> Int -> Forward m sh DIM1
 flowNetwork inputShape numHiddenLayers numHiddenNodes numClasses =
     inputLayer >-> innerLayers >-> preTopLayer >-> topLayer
-    where
-      inputLayer = innerForward $ newFC inputShape numHiddenNodes
-      innerLayers = flatInner $ P.fmap (\_ -> newFC (Z :. numHiddenNodes) numHiddenNodes) [1..numHiddenLayers]
-      preTopLayer = innerForward $ newFC (Z :. numHiddenNodes) numClasses
-      topLayer = topForward SoftMaxLayer
-      flatInner layers = P.foldl1 (>->) (P.fmap innerForward layers)
+        where
+          flatInner layers = P.foldl1 (>->) (P.fmap forward layers)
+          innerLayer = newFC (Z :. numHiddenNodes) numHiddenNodes
+          innerLayers = flatInner $ P.fmap (const innerLayer)
+                                           [1..numHiddenLayers]
+          inputLayer = forward $ newFC inputShape numHiddenNodes
+          preTopLayer = forward $ newFC (Z :. numHiddenNodes) numClasses
+          topLayer = forward SoftMaxLayer
diff --git a/deeplearning-hs.cabal b/deeplearning-hs.cabal
--- a/deeplearning-hs.cabal
+++ b/deeplearning-hs.cabal
@@ -3,7 +3,7 @@
 
 
 name:                deeplearning-hs
-version:             0.1.0.1
+version:             0.1.0.2
 description:         Implements type-safe deep neural networks
 synopsis:            Deep Learning in Haskell
 homepage:            https://github.com/ajtulloch/deeplearning-hs
