monad-memo-0.1.0: Control/Monad/Memo/Test/Main.hs
{-# LANGUAGE FlexibleInstances #-}
module Control.Monad.Memo.Test.Main
(
run
) where
import Test.QuickCheck
import System.Random
import Control.Monad.Memo
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.State
import Control.Monad.Cont
import Control.Monad.List
newtype SmallInt n = SmallInt { toInt::n } deriving Show
instance (Num n, Random n) => Arbitrary (SmallInt n) where
arbitrary = fmap SmallInt $ choose (0,10)
newtype SmallList a = SmallList { toList::[a] } deriving Show
instance Arbitrary a => Arbitrary (SmallList a) where
arbitrary = do
n <- choose (0,10)
ls <- arbitrary
return $ SmallList $ take n ls
-- | With ReaderT
fibr 0 = return 0
fibr 1 = return 1
fibr 2 = return 1
fibr n = do
p1 <- ask
p2 <- local (const (p1+1)) $ fibr (n-2)
f1 <- fibr (n-1)
f2 <- fibr (n-2)
return (p1+f1+f2+p2)
runFibr r = (`runReader`r) . fibr
fibmr 0 = return 0
fibmr 1 = return 1
fibmr 2 = return 1
fibmr n = do
p1 <- ask
p2 <- local (const (p1+1)) $ fibmr `memo` (n-2)
f1 <- fibmr `memo` (n-1)
f2 <- fibmr `memo` (n-2)
return (p1+f1+f2+p2)
runFibmr r = startEvalMemo . (`runReaderT`r) . fibmr
prop_ReaderEqv :: SmallInt Int -> SmallInt Int -> Bool
prop_ReaderEqv r n =
((`runReader`(toInt r)) . fibr $ (toInt n)) == (startEvalMemo . (`runReaderT`(toInt r)) . fibmr $ (toInt n))
-- | With WriterT
fibw 0 = return 0
fibw 1 = return 1
fibw n = do
f1 <- fibw (n-1)
f2 <- fibw (n-2)
tell $ show n
return (f1+f2)
fibmw 0 = return 0
fibmw 1 = return 1
fibmw n = do
f1 <- fibmw `memo` (n-1)
f2 <- fibmw `memo` (n-2)
tell $ show n
return (f1+f2)
prop_WriterEqv :: SmallInt Int -> Bool
prop_WriterEqv n =
(runWriter . fibw . toInt $ n) == (startEvalMemo . runWriterT . fibmw . toInt $ n)
-- | With ContT
fibc 0 = return 0
fibc 1 = return 1
fibc n = do
f1 <- fibc (n-1)
f2 <- callCC $ \ break -> do
if n == 4 then break 42 else fibc (n-2)
return (f1+f2)
fibmc 0 = return 0
fibmc 1 = return 1
fibmc n = do
f1 <- fibmc `memo` (n-1)
f2 <- callCC $ \ break -> do
if n == 4 then break 42 else fibmc `memo` (n-2)
return (f1+f2)
prop_ContEqv :: SmallInt Int -> Bool
prop_ContEqv n =
((`runCont`id) . fibc . toInt $ n) == (startEvalMemo . (`runContT`return) . fibmc . toInt $ n)
-- | With StateT
fibs 0 = return 0
fibs 1 = return 1
fibs n = do
s <- get
f1 <- fibs (n-1)
f2 <- fibs (n-2)
modify $ \s -> s+1
return (f1+f2+s)
fibms 0 = return 0
fibms 1 = return 1
fibms n = do
s <- get
f1 <- fibms `memo` (n-1)
f2 <- fibms `memo` (n-2)
modify $ \s -> s+1
return (f1+f2+s)
prop_StateEqv :: SmallInt Int -> SmallInt Int -> Bool
prop_StateEqv s n =
((`runState`(toInt s)) . fibs . toInt $ n) == (startEvalMemo . (`runStateT`(toInt s)) . fibms . toInt $ n)
-- | With ListT
--
data Tree a = Leaf !a | Fork (Tree a) (Tree a) deriving Eq
partitions as = [ splitAt n as | n <- [1..length as - 1 ]]
unfringe [a] = [Leaf a]
unfringe as = do
(l,k) <- partitions as
t <- unfringe l
u <- unfringe k
return (Fork t u)
unfringem [a] = return (Leaf a)
unfringem as = do
(l,k) <- ListT $ return (partitions as)
t <- unfringem `memo` l
u <- unfringem `memo` k
return (Fork t u)
prop_ListEqv :: SmallList Char -> Bool
prop_ListEqv ls =
unfringe (toList ls) == (startEvalMemo . runListT . unfringem $ (toList ls))
-- | Mutual recursion
f :: Int -> (Int,String)
f 0 = (1,"+")
f (n+1) =(g(n,fst(f n)),"-" ++ snd(f n))
g :: (Int, Int) -> Int
g (0, m) = m + 1
g (n+1,m) = fst(f n)-g(n,m)
type MemoF = MemoT Int (Int,String)
type MemoG = Memo (Int,Int) Int
type MemoFG = MemoF MemoG
fm :: Int -> MemoFG (Int,String)
fm 0 = return (1,"+")
fm (n+1) = do
fn <- fm `memol0` n
g <- gm `memol1` (n , fst fn)
return (g , "-" ++ snd fn)
gm :: (Int,Int) -> MemoFG Int
gm (0,m) = return (m+1)
gm (n+1,m) = do
fn <- fm `memol0` n
g <- gm `memol1` (n,m)
return $ fst fn - g
evalAll = startEvalMemo . startEvalMemoT
evalFm = evalAll . fm
evalGm = evalAll . gm
prop_MutualFEqv :: SmallInt Int -> Bool
prop_MutualFEqv sx = f x == evalFm x
where x = toInt sx
prop_MutualGEqv :: SmallInt Int -> SmallInt Int -> Bool
prop_MutualGEqv sx sy = g (x,y) == evalGm (x,y)
where
x = toInt sx
y = toInt sy
run :: IO ()
run = do
quickCheck prop_ReaderEqv
quickCheck prop_WriterEqv
quickCheck prop_ContEqv
quickCheck prop_StateEqv
quickCheck prop_ListEqv
quickCheck prop_MutualFEqv