Metric spaces defined over strings; i.e. edit distance.
> module Data.Metric.String (
>   Hamming(..),
>   Levenshtein(..),
>   RestrictedDamerauLevenshtein(..)
> ) where
> import Control.Applicative.Extras ((<$$>))
> import Data.Default (Default(def))
> import Data.Default.Instances.EditDistance ()
> import Data.Function (on)
> import Data.List.Extras (count)
> import Data.Metric.Class (Metric(..))
> import Data.Metric.Set (Discrete(..))
> import Text.EditDistance (levenshteinDistance, restrictedDamerauLevenshteinDistance)
`Hamming` wraps Hamming distance: the number of positions between two *fixed length* strings at which the corresponding symbols are different. Equivalently, this can be seen as the minimum number of substitutions required to change one of the strings into the other.
> newtype Hamming = Hamming
>   { getHamming :: String
>   } deriving (Eq, Show)
> instance Metric Hamming where
>   distance = count <$$> zipWith (distance `on` Discrete) `on` getHamming
`Levenshtein` wraps Levenshtein distance: the minimum number of single-character operations-- insertions, deletions or substitutions-- required to make two strings equal. Here, we in effect re-export the heavily optimised implementation provided by Max Bolingbroke's excellent `edit-distance` package.
> newtype Levenshtein = Levenshtein
>   { getLevenshtein :: String
>   } deriving (Eq, Show)
> instance Metric Levenshtein where
>   distance = fromIntegral <$$> levenshteinDistance def `on` getLevenshtein
The Restricted-Damerau Levenshtein distance extends Levenshtein distance (above), with an additional operation: the transposition of two adjacent characters. It is 'restricted' in that the algorithm computes the minimum number of edit operations **under the condition that no substring is edited more than once.** Here, again, we're wrapping an implementation from `edit-distance`.
> newtype RestrictedDamerauLevenshtein = RestrictedDamerauLevenshtein
>   { getRestrictedDamerauLevenshtein :: String
>   } deriving (Eq, Show)
> instance Metric RestrictedDamerauLevenshtein where
>   distance = fromIntegral <$$> restrictedDamerauLevenshteinDistance def `on` getRestrictedDamerauLevenshtein