{-# LANGUAGE ScopedTypeVariables, EmptyDataDecls #-} import Data.Function data Zero data Succ a class Nat a where toInt::a->Int instance Nat Zero where toInt = const 0 instance (Nat a) => Nat (Succ a) where toInt = const $ toInt (undefined::a) + 1 type One = Succ Zero type Two = Succ One type Three = Succ Two type Four = Succ Three type Five = Succ Four data ModNInt mod = MN {int::Int} deriving ( Eq, Ord) instance Show (ModNInt mod) where show = show . int instance (Nat mod) => Enum (ModNInt mod) where toEnum = MN . (`mod` toInt (undefined::mod)) fromEnum = int convop2 p x y = toEnum $ (p `on` fromEnum) x y instance (Nat mod) => Num (ModNInt mod) where (+) = convop2 (+) (-) = convop2 (-) (*) = convop2 (*) fromInteger = toEnum . fromInteger a = fromInteger 2 :: ModNInt Five b = fromInteger 3 :: ModNInt Five c = fromInteger 19 :: ModNInt Five main = print [a-b, a*b, a+b-c]