module Data.ChurchList where
import Prelude(Functor(..), Applicative(..), Monad(..), Bool(..), Maybe(..), (.), ($), id)
import qualified Prelude
import GHC.Magic(oneShot)
import GHC.Exts(build)
import Control.Monad(MonadPlus(..), liftM2)
import Control.Applicative(Alternative(..))
newtype ChurchList a =
ChurchList (forall b. (a -> b -> b) -> b -> b)
foldr :: (a -> b -> b) -> b -> ChurchList a -> b
foldr op e (ChurchList f) = eta (f op (eta e))
eta :: a -> a
eta x = x
nil :: ChurchList a
nil = ChurchList (\_ n -> n)
unit :: a -> ChurchList a
unit x = ChurchList (\c n -> c x n)
cons :: a -> ChurchList a -> ChurchList a
cons x xs = ChurchList (\c n -> c x (foldr c n xs))
append :: ChurchList a -> ChurchList a -> ChurchList a
append xs ys = ChurchList (\c n -> foldr c (foldr c n ys) xs)
join :: ChurchList (ChurchList a) -> ChurchList a
join xss = ChurchList (\c n -> foldr (\xs ys -> foldr c ys xs) n xss)
instance Functor ChurchList where
fmap f xs = ChurchList (\c n -> foldr (c . f) n xs)
instance Applicative ChurchList where
pure = return
(<*>) = liftM2 ($)
instance Monad ChurchList where
return = unit
xs >>= f = join (fmap f xs)
instance Alternative ChurchList where
empty = nil
(<|>) = append
instance MonadPlus ChurchList where
mzero = empty
mplus = (<|>)
fromList :: [a] -> ChurchList a
fromList xs = ChurchList (\c n -> Prelude.foldr c n xs)
toList :: ChurchList a -> [a]
toList (ChurchList f) = build f
foldl' :: (b -> a -> b) -> b -> ChurchList a -> b
foldl' op e xs =
foldr (\x f -> oneShot (\ (!acc) -> f (op acc x))) id xs e
filter :: (a -> Bool) -> ChurchList a -> ChurchList a
filter p xs =
ChurchList $ \c n ->
let
op x xs = if p x then c x xs else xs
in
foldr op n xs
fromMaybe :: Maybe a -> ChurchList a
fromMaybe Nothing = nil
fromMaybe (Just x) = unit x