{-# LANGUAGE NoMonomorphismRestriction, MultiParamTypeClasses, OverlappingInstances, IncoherentInstances, FlexibleInstances, FlexibleContexts, RankNTypes #-} import Control.Monad.Sharing import Data.Monadic.List main = do putStr "failing tests: " print . map fst . filter (not . snd) . zip [1..] $ tests where tests = [ dup_coin_let, dup_coin_bind, dup_coin_share , lazy_share, heads_bind, heads_share, dup_first_coin , one_coin, two_coins, dup_coin, dupnot_coin , first_rep, rep_coin , dup_list, ignore_shared, empty_rep , nest_lazy, nest_share1, nest_share2 , dup_dup, dup_two_coins, dup_head, dup_head_lazy ] instance Monad m => Shareable m (Int,Int) where shareArgs _ = return instance Monad m => Shareable m ([Int],[Int]) where shareArgs _ = return instance Monad m => Shareable m ((Int,Int),(Int,Int)) where shareArgs _ = return instance Monad m => Convertible m (Int,Int) (Int,Int) where convert = return instance (Monad m, Shareable m a) => Shareable m (m a, m a) where shareArgs f (x,y) = return (,) `ap` f x `ap` f y instance (Monad m, Convertible m a b) => Convertible m (m a, m a) (b, b) where convert (x,y) = return (,) `ap` (x >>= convert) `ap` (y >>= convert) -- assertEqual :: (Shareable (Lazy []) a, Convertible (Lazy []) a b, Eq b) -- => [b] -> Lazy [] a -> Bool assertEqual :: Eq a => [a] -> (forall s . Sharing s => s a) -> Bool assertEqual res test = zipEq (unsafeResults test) res where zipEq [] [] = True zipEq [] _ = False zipEq (_:_) [] = True zipEq (x:xs) (y:ys) = (x==y) && zipEq xs ys coin :: MonadPlus m => m Int coin = return 0 `mplus` return 1 -- examples from paper duplicate :: Monad m => m a -> m (a,a) duplicate a = do x <- a; y <- a; return (x,y) dup_coin_let = assertEqual [(0,0)::(Int,Int),(0,1),(1,0),(1,1)] $ let x = coin in duplicate x dup_coin_bind = assertEqual [(0,0)::(Int,Int),(1,1)] $ do x <- coin duplicate (return x) dup_coin_share = assertEqual [(0,0)::(Int,Int),(1,1)] $ do x <- share coin duplicate x -- strict_bind = -- diverges intentionally -- do x <- undefined :: Lazy [] Int -- duplicate (const (return 2) (return x)) lazy_share = assertEqual [(2::Int,2::Int)] $ do x <- share undef duplicate (const (return (2::Int)) x) undef :: Monad m => m Int undef = undefined dupl :: Monad m => m a -> m (List m a) dupl x = cons x (cons x nil) heads_bind = assertEqual [[0,0::Int],[0,1],[1,0],[1,1]] $ do x <- cons coin undefined dupl (first (return x)) >>= convert heads_share = assertEqual [[0,0::Int],[1,1]] $ do x <- share (cons coin undefined) dupl (first x) >>= convert coins :: MonadPlus m => m (List m Int) coins = nil `mplus` cons coin coins dup_first_coin = assertEqual [[0::Int,0],[1,1]] $ do cs <- share coins dupl (first cs) >>= convert -- other examples one_coin = assertEqual [0,1::Int] coin two_coins = assertEqual [(0,0),(0::Int,1::Int),(1,0),(1,1)] $ return (coin, coin) >>= convertPair where convertPair (a,b) = do x <- a; y <- b; return (x,y) dup_coin = assertEqual [(0::Int,0::Int),(1,1)] $ dup coin >>= convert dup :: (Monad m, Sharing m, Shareable m a) => m a -> m (m a, m a) dup a = do x <- share a return (x,x) dupnot_coin = assertEqual [(1::Int,1::Int),(0,0)] $ dupnot coin >>= convert dupnot a = do x <- share a return (liftM ((-)1) x, liftM ((-)1) x) first_rep = assertEqual [42::Int] $ first (first (rep (rep (return (42::Int))))) rep a = do x <- share a cons x (rep x) rep_coin = assertEqual [(0::Int,0::Int),(1,1)] $ do Cons x xs <- rep coin convert (x, first xs) dup_list = assertEqual [([],[]) ,([0::Int],[0::Int]) ,([0,0],[0,0]) ,([0,0,0],[0,0,0])] $ dup coins >>= convert ignore_shared = assertEqual [(0::Int,1::Int)] $ ign_pair mzero >>= convertPair where convertPair (a,b) = do x <- a; y <- b; return (x,y) ign_pair :: Sharing m => m Int -> m (m Int, m Int) ign_pair a = do x <- share a return (const (return 0) x, const (return 1) x) empty_rep = assertEqual [False] $ isEmpty (rep undef) nest_lazy = assertEqual [42::Int] $ do x <- share (cons (return 42) mzero) first x nest_share1 = assertEqual [(0::Int,0::Int),(1,1)] $ do x <- share (share (return True) >> coin) convert (x,x) nest_share2 = assertEqual [(0::Int,0::Int),(1,1)] $ do x <- share (share coin >>= id) convert (x,x) dup_dup = assertEqual [((0::Int,0::Int),(0::Int,0::Int)),((1,1),(1,1))] $ (dup (dup coin)) >>= convert dup_two_coins = assertEqual [((0::Int,0::Int),(0::Int,0::Int)),((0,1),(0,1)) ,((1,0),(1,0)),((1,1),(1,1))] $ do x <- share coin y <- share coin convertPair (return (x,y),return (x,y)) where convertPair (a,b) = do x <- a >>= convert; y <- b >>= convert; return (x,y) dup_head = assertEqual [(0::Int,0::Int),(1,1)] $ heads (cons coin nil) >>= convert heads l = do xs <- share l return (first xs, first xs) dup_head_lazy = assertEqual [(0::Int,0::Int),(1,1)] $ heads (cons coin undefined) >>= convert