Deciding whether a list of sum types is homogeneous
homogeneous could also be defined using pattern matching, though that would not necessarily be an improvement.

However, homogeneousButOne can definitely be simplified using pattern matching, with no need for Data.Map or Data.List.

data Foo = Bar | Baz | Quux | Id | Mix deriving (Eq, Ord, Show)

homogeneous :: [Foo] -&gt; Bool
homogeneous []           = True
homogeneous (Mix : _)    = False
homogeneous (Id  : xs)   = homogeneous xs
homogeneous (x   : [])   = True
homogeneous (a:Id:rest)  = homogeneous (a:rest)
homogeneous (a:b:rest)   = (a == b) &amp;&amp; homogeneous (b:rest)

homogeneousButOne :: [Foo] -&gt; (Foo, Foo, Bool)
homogeneousButOne xs
  | null nonId           = (Id, Id, True)
  | x' == Mix            = (Mix, Mix, False)
  | length nonId == 3    = majority2of3 nonId
  | homogeneous nonId    = (x', x', True)
  | homogeneous xs'      = (head xs', x', False)
  | x' == predominant    = (predominant, alt, False)
  | otherwise            = (Mix, Mix, False)
  where nonId = filter (/= Id) xs
        (x':xs') = nonId
        majority2of3 (a:b:c:[]) =
          if      a == b then (a, c, a == c)
          else if a == c then (a, b, a == b)
          else if b == c then (b, a, b == a)
          else                (Mix, Mix, False)
        (predominant, alt, _) = homogeneousButOne xs'