diff --git a/som.cabal b/som.cabal
--- a/som.cabal
+++ b/som.cabal
@@ -1,5 +1,5 @@
 name:           som
-version:        4.1
+version:        4.2
 synopsis:       Self-Organising Maps
 description:    A Kohonen Self-organising Map (SOM) maps input patterns 
                 onto a regular grid (usually two-dimensional) where each
@@ -31,7 +31,7 @@
                    base-unicode-symbols ==0.2.*,
                    binary == 0.5.* || == 0.6.* || == 0.7.*,
                    containers ==0.4.2.* || ==0.5.*,
-                   grid ==4.*,
+                   grid >=6.1 && ==6.*,
                    MonadRandom ==0.1.*
   ghc-options:     -Wall
   exposed-modules: Data.Datamining.Clustering.SOM,
@@ -46,7 +46,7 @@
                    QuickCheck ==2.5.* || ==2.6.*,
                    test-framework == 0.8.*,
                    som,
-                   grid ==4.*,
+                   grid >=6.1 && ==6.*,
                    base-unicode-symbols ==0.2.*,
                    MonadRandom ==0.1.*,
                    random ==1.0.*
diff --git a/src/Data/Datamining/Clustering/SOMInternal.hs b/src/Data/Datamining/Clustering/SOMInternal.hs
--- a/src/Data/Datamining/Clustering/SOMInternal.hs
+++ b/src/Data/Datamining/Clustering/SOMInternal.hs
@@ -11,7 +11,7 @@
 -- use @SOM@ instead. This module is subject to change without notice.
 --
 ------------------------------------------------------------------------
-{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts, 
+{-# LANGUAGE UnicodeSyntax, TypeFamilies, FlexibleContexts,
     FlexibleInstances, MultiParamTypeClasses #-}
 
 module Data.Datamining.Clustering.SOMInternal
@@ -41,8 +41,8 @@
 -- | A Self-Organising Map (SOM).
 --
 --   Although @SOM@ implements @GridMap@, most users will only need the
---   interface provided by @Classifier@. If you chose to use the 
---   @GridMap@ functions, please note:
+--   interface provided by @Data.Datamining.Clustering.Classifier@. If
+--   you chose to use the @GridMap@ functions, please note:
 --
 --   1. The functions @adjust@, and @adjustWithKey@ do not increment the
 --      counter. You can do so manually with @incrementCounter@.
@@ -63,11 +63,13 @@
 
 instance (G.Grid (gm p)) ⇒ G.Grid (SOM gm k p) where
   type Index (SOM gm k p) = G.Index (gm p)
+  type Direction (SOM gm k p) = G.Direction (gm p)
   indices = G.indices . sGridMap
   distance = G.distance . sGridMap
   neighbours = G.neighbours . sGridMap
   contains = G.contains . sGridMap
   viewpoint = G.viewpoint . sGridMap
+  directionTo = G.directionTo . sGridMap
   tileCount = G.tileCount . sGridMap
   null = G.null . sGridMap
   nonNull = G.nonNull . sGridMap
@@ -120,10 +122,10 @@
   where ds = GM.toList . GM.map (p `difference`) . sGridMap $ s
         bmu = fst . minimumBy (comparing snd) $ ds
 
-instance 
-  (GM.GridMap gm p, k ~ G.Index (GM.BaseGrid gm p), Pattern p, 
+instance
+  (GM.GridMap gm p, k ~ G.Index (GM.BaseGrid gm p), Pattern p,
   G.Grid (gm p), GM.GridMap gm (Metric p), k ~ G.Index (gm p),
-  k ~ G.Index (GM.BaseGrid gm (Metric p)), Ord (Metric p)) ⇒ 
+  k ~ G.Index (GM.BaseGrid gm (Metric p)), Ord (Metric p)) ⇒
     Classifier (SOM gm) k p where
   toList = GM.toList . sGridMap
   numModels = G.tileCount . sGridMap
@@ -154,16 +156,16 @@
 --   We recommend setting this parameter to the number of patterns
 --   (or pattern batches) that will be presented to the classifier. An
 --   estimate is fine.
-defaultSOM 
+defaultSOM
   ∷ Floating (Metric p) ⇒ gm p → Metric p → Metric p → Int → SOM gm k p
-defaultSOM gm r w t = 
-  SOM { 
-        sGridMap=gm, 
-        sLearningFunction=decayingGaussian r w t, 
+defaultSOM gm r w t =
+  SOM {
+        sGridMap=gm,
+        sLearningFunction=decayingGaussian r w t,
         sCounter=0
       }
 
--- | Creates a classifier with a custom learning function. 
+-- | Creates a classifier with a custom learning function.
 --   Usage is @'customSOM' gm g@, where:
 --
 --   [@gm@] The geometry and initial models for this classifier.
@@ -172,8 +174,8 @@
 --
 --   [@f@] A function used to adjust the models in the classifier.
 --   This function will be invoked with two parameters.
---   The first parameter will indicate how many patterns (or pattern 
---   batches) have previously been presented to this classifier. 
+--   The first parameter will indicate how many patterns (or pattern
+--   batches) have previously been presented to this classifier.
 --   Typically this is used to make the learning rate decay over time.
 --   The second parameter to the function is the grid distance from
 --   the node being updated to the BMU (Best Matching Unit).
@@ -181,22 +183,21 @@
 --   which the node's model should be updated to match the target).
 --   The learning rate should be between zero and one.
 customSOM ∷ gm p → (Int → Int → Metric p) → SOM gm k p
-customSOM gm f = 
+customSOM gm f =
   SOM {
         sGridMap=gm,
         sLearningFunction=f,
         sCounter=0
       }
 
-
 -- | Calculates @r/e/^(-d^2/2w^2)@.
 --   This form of the Gaussian function is useful as a learning rate
 --   function. In @'gaussian' r w d@, @r@ specifies the highest learning
 --   rate, which will be applied to the SOM node that best matches the
---   input pattern. The learning rate applied to other nodes will be 
---   applied based on their distance @d@ from the best matching node. 
+--   input pattern. The learning rate applied to other nodes will be
+--   applied based on their distance @d@ from the best matching node.
 --   The value @w@ controls the \'width\' of the Gaussian. Higher values
---   of @w@ cause the learning rate to fall off more slowly with 
+--   of @w@ cause the learning rate to fall off more slowly with
 --   distance @d@.
 gaussian ∷ Floating a ⇒ a → a → Int → a
 gaussian r w d = r * exp (-d'*d'/(2*w*w))
@@ -204,14 +205,12 @@
 
 -- | Configures a typical learning function for classifiers.
 --   @'decayingGaussian' r w0 tMax@ returns a bell curve-shaped
---   function. At time zero, the maximum learning rate (applied to the 
+--   function. At time zero, the maximum learning rate (applied to the
 --   BMU) is @r@, and the neighbourhood width is @w@. Over time the bell
 --   curve shrinks and the learning rate tapers off, until at time
 --   @tMax@, the learning rate is negligible.
 decayingGaussian
   ∷ Floating a ⇒ a → a → Int → (Int → Int → a)
-decayingGaussian r w0 tMax = 
+decayingGaussian r w0 tMax =
   \t d → let t' = fromIntegral t in gaussian r w0 d * exp (-t'/tMax')
   where tMax' = fromIntegral tMax
-
-
diff --git a/src/Data/Datamining/Pattern.hs b/src/Data/Datamining/Pattern.hs
--- a/src/Data/Datamining/Pattern.hs
+++ b/src/Data/Datamining/Pattern.hs
@@ -16,19 +16,23 @@
   (
     -- * Patterns
     Pattern(..),
+    -- * Numbers as patterns
+    -- $Num
+    adjustNum,
+    absDifference,
     -- * Numeric vectors as patterns
+    -- ** Raw vectors
+    -- $Vector
+    adjustVector,
+    euclideanDistanceSquared,
+    magnitudeSquared,
     -- ** Normalised vectors
     NormalisedVector,
     normalise,
     -- ** Scaled vectors
     ScaledVector,
     scale,
-    scaleAll,
-    -- ** Useful functions
-    -- $Vector
-    adjustVector,
-    euclideanDistanceSquared,
-    magnitudeSquared
+    scaleAll
   ) where
 
 import Data.Eq.Unicode ((≡))
@@ -37,35 +41,63 @@
 -- | A pattern to be learned or classified.
 class Pattern p where
   type Metric p
-  -- | Compares two patterns and returns a /non-negative/ number 
-  --   representing how different the patterns are. A result of @0@ 
+  -- | Compares two patterns and returns a /non-negative/ number
+  --   representing how different the patterns are. A result of @0@
   --   indicates that the patterns are identical.
   difference ∷ p → p → Metric p
   -- | @'makeSimilar' target amount pattern@ returns a modified copy of
-  --   @pattern@ that is more similar to @target@ than @pattern@ is. The 
-  --   magnitude of the adjustment is controlled by the @amount@ 
-  --   parameter, which should be a number between 0 and 1. Larger 
+  --   @pattern@ that is more similar to @target@ than @pattern@ is. The
+  --   magnitude of the adjustment is controlled by the @amount@
+  --   parameter, which should be a number between 0 and 1. Larger
   --   values for @amount@ permit greater adjustments. If @amount@=1,
   --   the result should be identical to the @target@. If @amount@=0,
   --   the result should be the unmodified @pattern@.
   makeSimilar ∷ p → Metric p → p → p
 
 --
+-- Using numbers as patterns.
+--
+
+absDifference :: Num a => a -> a -> a
+absDifference x y = abs (x - y)
+
+adjustNum :: (Num a, Ord a, Eq a) => a -> a -> a -> a
+adjustNum target r x
+  | r < 0     = error "Negative learning rate"
+  | r > 1     = error "Learning rate > 1"
+  | r ≡ 1     = x
+  | otherwise = adjustNum' r target x
+
+-- Note that parameters are swapped
+adjustNum' :: Num a => a -> a -> a -> a
+adjustNum' r target x = x + r*(target - x)
+
+{- $Num
+If you wish to use, say, a @Double@ as a pattern, one option is to
+use @no-warn-orphans@ and add the following to your code:
+
+> instance Double ⇒ Pattern Double where
+>   type Metric Double = Double
+>   difference = euclideanDistanceSquared
+>   makeSimilar = adjustVector
+-}
+
+--
 -- Using numeric vectors as patterns.
--- 
+--
 
 magnitudeSquared ∷ Num a ⇒ [a] → a
 magnitudeSquared xs =  sum $ map (\x → x*x) xs
 
--- | Calculates the square of the Euclidean distance between two 
+-- | Calculates the square of the Euclidean distance between two
 --   vectors.
 euclideanDistanceSquared ∷ Num a ⇒ [a] → [a] → a
 euclideanDistanceSquared xs ys = magnitudeSquared $ zipWith (-) xs ys
 
--- | @'adjustVector' target amount vector@ adjusts @vector@ to move it 
+-- | @'adjustVector' target amount vector@ adjusts @vector@ to move it
 --   closer to @target@. The amount of adjustment is controlled by the
 --   learning rate @r@, which is a number between 0 and 1. Larger values
---   of @r@ permit more adjustment. If @r@=1, the result will be 
+--   of @r@ permit more adjustment. If @r@=1, the result will be
 --   identical to the @target@. If @amount@=0, the result will be the
 --   unmodified @pattern@.
 adjustVector ∷ (Num a, Ord a, Eq a) ⇒ [a] → a → [a] → [a]
@@ -73,11 +105,9 @@
   | r < 0     = error "Negative learning rate"
   | r > 1     = error "Learning rate > 1"
   | r ≡ 1     = xs
-  | otherwise = zipWith (+) ys deltas
-      where ds = zipWith (-) xs ys
-            deltas = map (r *) ds
+  | otherwise = zipWith (adjustNum' r) xs ys
 
--- | A vector that has been normalised, i.e., the magnitude of the 
+-- | A vector that has been normalised, i.e., the magnitude of the
 --   vector = 1.
 data NormalisedVector a = NormalisedVector [a] deriving Show
 
@@ -90,31 +120,31 @@
 norm xs = sqrt $ sum (map f xs)
   where f x = x*x
 
-instance (Floating a, Fractional a, Ord a, Eq a) ⇒ 
+instance (Floating a, Fractional a, Ord a, Eq a) ⇒
     Pattern (NormalisedVector a) where
   type Metric (NormalisedVector a) = a
-  difference (NormalisedVector xs) (NormalisedVector ys) = 
+  difference (NormalisedVector xs) (NormalisedVector ys) =
     euclideanDistanceSquared xs ys
-  makeSimilar (NormalisedVector xs) r (NormalisedVector ys) = 
+  makeSimilar (NormalisedVector xs) r (NormalisedVector ys) =
     normalise $ adjustVector xs r ys
 
--- | A vector that has been scaled so that all elements in the vector 
---   are between zero and one. To scale a set of vectors, use 
---   @'scaleAll'@. Alternatively, if you can identify a maximum and 
---   minimum value for each element in a vector, you can scale 
+-- | A vector that has been scaled so that all elements in the vector
+--   are between zero and one. To scale a set of vectors, use
+--   @'scaleAll'@. Alternatively, if you can identify a maximum and
+--   minimum value for each element in a vector, you can scale
 --   individual vectors using @'scale'@.
 data ScaledVector a = ScaledVector [a] deriving Show
 
 -- | Given a vector @qs@ of pairs of numbers, where each pair represents
---   the maximum and minimum value to be expected at each index in 
---   @xs@, @'scale' qs xs@ scales the vector @xs@ element by element, 
+--   the maximum and minimum value to be expected at each index in
+--   @xs@, @'scale' qs xs@ scales the vector @xs@ element by element,
 --   mapping the maximum value expected at that index to one, and the
 --   minimum value to zero.
 scale ∷ Fractional a ⇒ [(a,a)] → [a] → ScaledVector a
 scale qs xs = ScaledVector $ zipWith scaleValue qs xs
 
 -- | Scales a set of vectors by determining the maximum and minimum
---   values at each index in the vector, and mapping the maximum 
+--   values at each index in the vector, and mapping the maximum
 --   value to one, and the minimum value to zero.
 scaleAll ∷ (Fractional a, Ord a) ⇒ [[a]] → [ScaledVector a]
 scaleAll xss = map (scale qs) xss
@@ -133,17 +163,17 @@
 
 instance (Fractional a, Ord a, Eq a) ⇒ Pattern (ScaledVector a) where
   type Metric (ScaledVector a) = a
-  difference (ScaledVector xs) (ScaledVector ys) = 
+  difference (ScaledVector xs) (ScaledVector ys) =
     euclideanDistanceSquared xs ys
   makeSimilar (ScaledVector xs) r (ScaledVector ys) =
     ScaledVector $ adjustVector xs r ys
 
 {- $Vector
-If you wish to use raw numeric vectors as a pattern, use
-@no-warn-orphans@ and add the following to your code:
+If you wish to use raw numeric vectors as a pattern, one option is to
+use @no-warn-orphans@ and add the following to your code:
 
-> instance (Floating a, Fractional a, Ord a, Eq a) ⇒ Pattern [a] a where
+> instance (Floating a, Fractional a, Ord a, Eq a) ⇒ Pattern [a] where
+>   type Metric [a] = a
 >   difference = euclideanDistanceSquared
 >   makeSimilar = adjustVector
 -}
-
