Skip to content

Instantly share code, notes, and snippets.

@linusyang
Created November 26, 2015 08:59
Show Gist options
  • Select an option

  • Save linusyang/5aa190633b5deb2948c5 to your computer and use it in GitHub Desktop.

Select an option

Save linusyang/5aa190633b5deb2948c5 to your computer and use it in GitHub Desktop.

Revisions

  1. linusyang created this gist Nov 26, 2015.
    71 changes: 71 additions & 0 deletions Nat.hs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,71 @@
    {-# LANGUAGE RankNTypes #-}
    module Nat where

    import Prelude hiding (succ, pred)

    class Nat a where
    zero :: a
    succ :: a -> a
    pred :: a -> a
    fold :: (b -> b) -> b -> a -> b

    toInt :: a -> Int
    toInt = fold (+ 1) 0

    toNat :: Int -> a
    toNat 0 = zero
    toNat n = succ (toNat (n - 1))

    -- Church Encoding
    newtype CNat = CNat { unCNat :: forall a . (a -> a) -> a -> a }

    instance Nat CNat where
    zero = CNat (\f x -> x)
    succ nat = CNat (\f x -> f (unCNat nat f x))
    pred nat = CNat (\f x -> unCNat nat (\g h -> h (g f)) (const x) id)
    fold s z nat = unCNat nat s z

    -- Scott Encoding
    newtype SNat = SNat { unSNat :: forall b . (SNat -> b) -> b -> b }

    instance Nat SNat where
    zero = SNat (\f x -> x)
    succ nat = SNat (\f x -> f nat)
    fold s z nat = unSNat nat (\p -> s (fold s z p)) z
    pred nat = SNat (unSNat nat unSNat undefined)

    -- Parigot Encoding
    newtype PNat = PNat { unPNat :: forall b . (b -> PNat -> b) -> b -> b }

    instance Nat PNat where
    zero = PNat (\f x -> x)
    succ nat = PNat (\f x -> f (unPNat nat f x) nat)
    fold s z nat = unPNat nat (\n p -> s n) z
    pred nat = unPNat nat (\n p -> p) undefined

    -- Alternative Encoding
    newtype ANat = ANat { unANat :: forall b . ((ANat -> b) -> ANat -> b) -> b -> b }

    instance Nat ANat where
    zero = ANat (\f x -> x)
    succ nat = ANat (\f x -> f (\c -> unANat c f x) nat)
    fold s z nat = unANat nat (\cont p -> s (cont p)) z
    pred nat = unANat nat (\cont p -> p) undefined

    -- Tests
    testNat :: Nat a => a -> IO ()
    testNat x = let printNat n = putStr (show . toInt $ n) >> putStr " " in
    do printNat x
    printNat $ pred x
    printNat $ succ x
    putStrLn []

    test :: IO ()
    test = do
    testNat (toNat 3 :: CNat)
    testNat (toNat 3 :: SNat)
    testNat (toNat 3 :: PNat)
    testNat (toNat 3 :: ANat)

    main :: IO ()
    main = test