diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,16 @@
+0.2.1
+-----
+* Added a changelog.
+* Added `hamming` distance metric.
+* Added instance of `Semigroupoid`. (@tonymorris)
+* Fixed hlint warnings.
+
+0.2
+---
+* Fixed types of `discrete` and `levenshtein` to use `Integral` instead of
+  `Floating`.
+* Slight docs formatting fixes
+
+0.1
+---
+Initial release.
diff --git a/ms.cabal b/ms.cabal
--- a/ms.cabal
+++ b/ms.cabal
@@ -1,5 +1,5 @@
 name:                ms
-version:             0.2
+version:             0.2.1
 synopsis:            metric spaces
 description:
   A 'MetricSpace' is a set together with a notion of distance between
@@ -26,6 +26,7 @@
 category:            Math
 build-type:          Simple
 cabal-version:       >= 1.10
+extra-source-files:  CHANGELOG.md
 
 source-repository head
   type:     git
@@ -39,6 +40,7 @@
                      , edit-distance >= 0.2 && < 0.3
                      , lens >= 4 && < 5
                      , profunctors >= 5 && < 6
+                     , semigroupoids >= 3 && < 6
                      , semigroups >= 0.12 && < 0.17
                      , vector >= 0.10 && < 0.12
   hs-source-dirs:      src
diff --git a/src/Math/MetricSpace.hs b/src/Math/MetricSpace.hs
--- a/src/Math/MetricSpace.hs
+++ b/src/Math/MetricSpace.hs
@@ -37,6 +37,7 @@
 import Data.Functor.Contravariant.Divisible
 import Data.Profunctor
 import Data.Semigroup
+import Data.Semigroupoid
 import qualified Data.Vector as V
 import Text.EditDistance
 
@@ -91,6 +92,10 @@
   rmap f (MetricSpace b) = MetricSpace (\x y -> f (b x y))
   {-# INLINE rmap #-}
 
+instance Semigroupoid MetricSpace where
+  MetricSpace m1 `o` MetricSpace m2 =
+    MetricSpace (\a1 a2 -> let b = m2 a1 a2 in m1 b b)
+
 _FlippedMetricSpace
   :: Iso
      (MetricSpace a b)
@@ -123,17 +128,17 @@
 instance SwappedMetricSpace MetricSpace where
   _SwappedMetricSpace =
     iso
-      (\(MetricSpace m) -> MetricSpace (\a1 a2 -> m a2 a1))
-      (\(MetricSpace m) -> MetricSpace (\a2 a1 -> m a1 a2))
+      (\(MetricSpace m) -> MetricSpace (flip m))
+      (\(MetricSpace m) -> MetricSpace (flip m))
   {-# INLINE _SwappedMetricSpace #-}
 
 instance SwappedMetricSpace FlippedMetricSpace where
   _SwappedMetricSpace =
     iso
       (\(FlippedMetricSpace (MetricSpace m)) ->
-         FlippedMetricSpace (MetricSpace (\a1 a2 -> m a2 a1)))
+         FlippedMetricSpace (MetricSpace (flip m)))
       (\(FlippedMetricSpace (MetricSpace m)) ->
-         FlippedMetricSpace (MetricSpace (\a1 a2 -> m a2 a1)))
+         FlippedMetricSpace (MetricSpace (flip m)))
   {-# INLINE _SwappedMetricSpace #-}
 
 -- | Levenshtein distance between 'String's.
@@ -187,3 +192,12 @@
   where
     f a b = V.sum (V.zipWith (\x y -> abs (x-y)) a b)
 {-# INLINE taxicab #-}
+
+-- | Hamming distance over n-dimensional 'Vector's.
+hamming :: (Eq a, Integral b) => MetricSpace (V.Vector a) b
+hamming =
+  MetricSpace (\x y ->
+                 fromIntegral .
+                 V.length .
+                 V.filter (uncurry (/=)) $ V.zip x y)
+{-# INLINE hamming #-}
diff --git a/tests/test.hs b/tests/test.hs
--- a/tests/test.hs
+++ b/tests/test.hs
@@ -72,6 +72,7 @@
     -- Integer
   , testGroup "Integer" [
       genTestGroupV "discrete" (discrete :: MetricSpace (V.Vector Integer) Integer)
+    , genTestGroupV "hamming" (hamming :: MetricSpace (V.Vector Char) Integer)
     ]
 
     -- Double
