{-# LANGUAGE Rank2Types, BangPatterns #-}
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)
{-# INLINE foldr #-}
foldr :: (a -> b -> b) -> b -> ChurchList a -> b
foldr op e (ChurchList f) = eta (f op (eta e))
{-# INLINE[0] eta #-}
eta :: a -> a
eta x = x
{-# RULES "eta" forall f. eta f = \x -> f x #-}
{-# INLINE nil #-}
nil :: ChurchList a
nil = ChurchList (\_ n -> n)
{-# INLINE unit #-}
unit :: a -> ChurchList a
unit x = ChurchList (\c n -> c x n)
{-# INLINE cons #-}
cons :: a -> ChurchList a -> ChurchList a
cons x xs = ChurchList (\c n -> c x (foldr c n xs))
{-# INLINE append #-}
append :: ChurchList a -> ChurchList a -> ChurchList a
append xs ys = ChurchList (\c n -> foldr c (foldr c n ys) xs)
{-# INLINE join #-}
join :: ChurchList (ChurchList a) -> ChurchList a
join xss = ChurchList (\c n -> foldr (\xs ys -> foldr c ys xs) n xss)
instance Functor ChurchList where
{-# INLINE fmap #-}
fmap f xs = ChurchList (\c n -> foldr (c . f) n xs)
instance Applicative ChurchList where
{-# INLINE pure #-}
pure = return
{-# INLINE (<*>) #-}
(<*>) = liftM2 ($)
instance Monad ChurchList where
{-# INLINE return #-}
return = unit
{-# INLINE (>>=) #-}
xs >>= f = join (fmap f xs)
instance Alternative ChurchList where
{-# INLINE empty #-}
empty = nil
{-# INLINE (<|>) #-}
(<|>) = append
instance MonadPlus ChurchList where
{-# INLINE mzero #-}
mzero = empty
{-# INLINE mplus #-}
mplus = (<|>)
{-# INLINE fromList #-}
fromList :: [a] -> ChurchList a
fromList xs = ChurchList (\c n -> Prelude.foldr c n xs)
{-# INLINE toList #-}
toList :: ChurchList a -> [a]
toList (ChurchList f) = build f
{-# INLINE foldl' #-}
foldl' :: (b -> a -> b) -> b -> ChurchList a -> b
foldl' op e xs =
foldr (\x f -> oneShot (\ (!acc) -> f (op acc x))) id xs e
{-# INLINE filter #-}
filter :: (a -> Bool) -> ChurchList a -> ChurchList a
filter p xs =
ChurchList $ \c n ->
let
{-# INLINE op #-}
op x xs = if p x then c x xs else xs
in
foldr op n xs
{-# INLINE fromMaybe #-}
fromMaybe :: Maybe a -> ChurchList a
fromMaybe Nothing = nil
fromMaybe (Just x) = unit x