diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,6 +1,10 @@
 Revision history for Haskell package learning-hmm
 ===
 
+## Version 0.3.2.0
+- Add function `euclideanDistance` which measures the Euclidean distance between
+  two models
+
 ## Version 0.3.1.3
 - Bug fix release
 
diff --git a/learning-hmm.cabal b/learning-hmm.cabal
--- a/learning-hmm.cabal
+++ b/learning-hmm.cabal
@@ -1,5 +1,5 @@
 name:                learning-hmm
-version:             0.3.1.3
+version:             0.3.2.0
 stability:           experimental
 
 synopsis:            Yet another library for hidden Markov models
diff --git a/src/Learning/HMM.hs b/src/Learning/HMM.hs
--- a/src/Learning/HMM.hs
+++ b/src/Learning/HMM.hs
@@ -5,6 +5,7 @@
   , LogLikelihood
   , init
   , withEmission
+  , euclideanDistance
   , viterbi
   , baumWelch
   , baumWelch'
@@ -82,6 +83,16 @@
     model'   = toInternal model
     xs'      = U.fromList $ fromJust $ mapM (`V.elemIndex` outputs') xs
 
+-- | Return the Euclidean distance between two models that have the same
+--   states and outputs.
+euclideanDistance :: (Eq s, Eq o) => HMM s o -> HMM s o -> Double
+euclideanDistance model1 model2 =
+  checkTwoModelsIn "euclideanDistance" model1 model2 `seq`
+  I.euclideanDistance model1' model2'
+  where
+    model1' = toInternal model1
+    model2' = toInternal model2
+
 -- | @viterbi model xs@ performs the Viterbi algorithm using the observed
 --   outputs @xs@, and returns the most likely state path and its log
 --   likelihood.
@@ -144,6 +155,18 @@
   | null states  = errorIn fun "empty states"
   | null outputs = errorIn fun "empty outputs"
   | otherwise    = ()
+
+-- | Check if the two models have the same states and outputs.
+checkTwoModelsIn :: (Eq s, Eq o) => String -> HMM s o -> HMM s o -> ()
+checkTwoModelsIn fun model model'
+  | ss /= ss' = errorIn fun "states disagree"
+  | os /= os' = errorIn fun "outputs disagree"
+  | otherwise = ()
+  where
+    ss  = states model
+    ss' = states model'
+    os  = outputs model
+    os' = outputs model'
 
 -- | Check if all the elements of the observed outputs are contained in the
 --   'outputs' of the model.
diff --git a/src/Learning/HMM/Internal.hs b/src/Learning/HMM/Internal.hs
--- a/src/Learning/HMM/Internal.hs
+++ b/src/Learning/HMM/Internal.hs
@@ -5,6 +5,7 @@
   , LogLikelihood
   , init
   , withEmission
+  , euclideanDistance
   , viterbi
   , baumWelch
   , baumWelch'
@@ -89,7 +90,6 @@
 
     model' = fst $ head $ dropWhile ((> 1e-9) . snd) $ zip ms' ds
 
--- | Return the Euclidean distance between two models.
 euclideanDistance :: HMM -> HMM -> Double
 euclideanDistance model model' =
   sqrt $ H.sumElements ((w - w') ** 2) + H.sumElements ((phi - phi') ** 2)
diff --git a/src/Learning/IOHMM.hs b/src/Learning/IOHMM.hs
--- a/src/Learning/IOHMM.hs
+++ b/src/Learning/IOHMM.hs
@@ -5,6 +5,7 @@
   , LogLikelihood
   , init
   , withEmission
+  , euclideanDistance
   , viterbi
   , baumWelch
   , baumWelch'
@@ -93,6 +94,16 @@
     xs'      = U.fromList $ fromJust $ mapM (`V.elemIndex` inputs') xs
     ys'      = U.fromList $ fromJust $ mapM (`V.elemIndex` outputs') ys
 
+-- | Return the Euclidean distance between two models that have the same
+--   inputs, states, and outputs.
+euclideanDistance :: (Eq i, Eq s, Eq o) => IOHMM i s o -> IOHMM i s o -> Double
+euclideanDistance model1 model2 =
+  checkTwoModelsIn "euclideanDistance" model1 model2 `seq`
+  I.euclideanDistance model1' model2'
+  where
+    model1' = toInternal model1
+    model2' = toInternal model2
+
 -- | @viterbi model xs ys@ performs the Viterbi algorithm using the inputs
 --   @xs@ and outputs @ys@, and returns the most likely state path and its
 --   log likelihood.
@@ -167,6 +178,21 @@
   | null states  = errorIn fun "empty states"
   | null outputs = errorIn fun "empty outputs"
   | otherwise    = ()
+
+-- | Check if the two models have the same inputs, states, and outputs.
+checkTwoModelsIn :: (Eq i, Eq s, Eq o) => String -> IOHMM i s o -> IOHMM i s o -> ()
+checkTwoModelsIn fun model model'
+  | is /= is' = errorIn fun "inputs disagree"
+  | ss /= ss' = errorIn fun "states disagree"
+  | os /= os' = errorIn fun "outputs disagree"
+  | otherwise = ()
+  where
+    is  = inputs model
+    is' = inputs model'
+    ss  = states model
+    ss' = states model'
+    os  = outputs model
+    os' = outputs model'
 
 -- | Check if all the elements of the given inputs (outputs) are contained
 --   in the 'inputs' ('outputs') of the model.
diff --git a/src/Learning/IOHMM/Internal.hs b/src/Learning/IOHMM/Internal.hs
--- a/src/Learning/IOHMM/Internal.hs
+++ b/src/Learning/IOHMM/Internal.hs
@@ -5,6 +5,7 @@
   , LogLikelihood
   , init
   , withEmission
+  , euclideanDistance
   , viterbi
   , baumWelch
   , baumWelch'
@@ -93,7 +94,6 @@
 
     model' = fst $ head $ dropWhile ((> 1e-9) . snd) $ zip ms' ds
 
--- | Return the Euclidean distance between two models.
 euclideanDistance :: IOHMM -> IOHMM -> Double
 euclideanDistance model model' =
   sqrt $ sum $ H.sumElements ((phi - phi') ** 2) :
