Skip to content

Instantly share code, notes, and snippets.

@aaronjeline
Last active August 14, 2018 13:40
Show Gist options
  • Save aaronjeline/ed2a11f21518e6eee28d4f689aa8e514 to your computer and use it in GitHub Desktop.
Save aaronjeline/ed2a11f21518e6eee28d4f689aa8e514 to your computer and use it in GitHub Desktop.
Church Numerals in Haskell
data N = Z | S N
-- Naturals are equitable
instance Eq N where
(==) Z Z = True
(==) (S a) (S b) = a == b
(==) (S n) _ = False
(==) _ (S n) = False
-- Naturals are ordered
instance Ord N where
(<=) Z Z = True
(<=) (S a) (S b) = a <= b
(<=) Z (S b) = True
(<=) (S a) Z = False
-- Naturals can be displayed
instance Show N where
show = show . nToInt
-- Wrap a function that operates on Naturals to operating on Ints
intWrapper :: (N -> N -> Maybe N) -> (Int -> Int -> Maybe Int)
intWrapper f = \ia ib ->
do
na <- intToN ia
nb <- intToN ib
result <- f na nb
return $ nToInt result
justWrapper :: (N -> N -> N) -> (N -> N -> Maybe N)
justWrapper f = \a b -> Just $ f a b
-- Converts an integer to a Natural, if it's >= 0
intToN :: Int -> Maybe N
intToN n
| n == 0 = Just Z
| n > 0 = do
sub <- intToN (n - 1)
return $ S sub
| otherwise = Nothing
nToInt :: N -> Int
nToInt Z = 0
nToInt (S n) = 1 + (nToInt n)
add :: N -> N -> N
add Z a = a
add a Z = a
add a (S b) = (S (add a b))
minus :: N -> N -> Maybe N
minus Z (S n) = Nothing
minus n Z = Just n
minus (S a) (S b) = minus a b
multiply :: N -> N -> N
multiply Z a = Z
multiply a Z = Z
multiply (S Z) a = a
multiply a (S Z) = a
multiply a (S b) = add a (multiply a b)
-- Simple datatype to hold the two division results
data DivInfo = Info N N deriving (Show)
ratio :: N -> N -> Maybe DivInfo
ratio n (S Z) = Just $ Info n Z
ratio a b
| b == Z = Nothing
| a > b = do
sub <- (minus a b)
term <- (ratio sub b)
case term of (Info amnt rem) -> return (Info (S amnt) rem)
| a == b = Just (Info (S Z) Z)
| a < b = Just (Info Z a)
divide :: N -> N -> Maybe N
divide a b = do
(Info amnt rem) <- (ratio a b)
return amnt
modulo :: N -> N -> Maybe N
modulo a b = do
(Info amnt rem) <- (ratio a b)
return rem
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment