{-# LANGUAGE TemplateHaskell, KindSignatures, TypeFamilies #-} {-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-} module Main where import Data.Functor.Foldable import Data.Functor.Foldable.TH import Data.List (foldl') import Test.HUnit data Expr a = Lit a | Add (Expr a) (Expr a) | Expr a :* [Expr a] deriving (Show) makeBaseFunctor ''Expr expr1 :: Expr Int expr1 = Add (Lit 2) (Lit 3 :* [Lit 4]) -- This is to test newtype derivation -- -- Kind of a list newtype L a = L { getL :: Maybe (a, L a) } deriving (Show, Eq) makeBaseFunctor ''L cons :: a -> L a -> L a cons x xs = L (Just (x, xs)) nil :: L a nil = L Nothing main :: IO () main = do let expr2 = ana divCoalg 55 :: Expr Int 14 @=? cata evalAlg expr1 55 @=? cata evalAlg expr2 let lBar = cons 'b' $ cons 'a' $ cons 'r' $ nil "bar" @=? cata lAlg lBar lBar @=? ana lCoalg "bar" where evalAlg (LitF x) = x evalAlg (AddF x y) = x + y evalAlg (x :*$ y) = foldl' (*) x y divCoalg x | x < 5 = LitF x | even x = 2 :*$ [x'] | otherwise = AddF x' (x - x') where x' = x `div` 2 lAlg (LF Nothing) = [] lAlg (LF (Just (x, xs))) = x : xs lCoalg [] = LF { getLF = Nothing } -- to test field renamer lCoalg (x : xs) = LF { getLF = Just (x, xs) }