module Numeric.Distance
( Dist(..)
, Distance(..)
, adjacent
) where
import Data.Int (Int8, Int16, Int32, Int64)
data Distance
= NegativeInfinite
| Finite Int
| PositiveInfinite
deriving (Eq, Ord)
class Ord a => Dist a where
distance :: a -> a -> Distance
shift :: Int -> a -> Maybe a
instance Dist Int where
distance m n = Finite (n - m)
shift m n = Just (m + n)
instance Dist Int8 where
distance = integralDistance
shift = integralShift
instance Dist Int16 where
distance = integralDistance
shift = integralShift
instance Dist Int32 where
distance = integralDistance
shift = integralShift
instance Dist Int64 where
distance = integralDistance
shift = integralShift
instance Dist Integer where
distance m n = Finite (fromInteger (n - m))
shift m n = Just (toInteger m + n)
instance Dist Float where
distance = uncountableDistance
shift = uncountableShift
instance Dist Double where
distance = uncountableDistance
shift = uncountableShift
integralDistance :: Integral a => a -> a -> Distance
integralDistance m n = Finite (fromIntegral n - fromIntegral m)
integralShift :: Num a => Int -> a -> Maybe a
integralShift m n = Just (fromIntegral m + n)
uncountableDistance :: Ord a => a -> a -> Distance
uncountableDistance m n
| m == n = Finite 0
| m < n = PositiveInfinite
| otherwise = NegativeInfinite
uncountableShift :: Int -> a -> Maybe a
uncountableShift 0 m = Just m
uncountableShift _ _ = Nothing
adjacent :: Dist a => a -> a -> Bool
adjacent a b = distance a b == Finite 1