From 8e21f0c826b5ce5fc5886d9a4969fcf1ad80c475 Mon Sep 17 00:00:00 2001 From: Sebastian Fischer Date: Thu, 30 Jun 2011 17:29:57 +0900 Subject: [PATCH] updated implementation to reflect final version for JFP special issue --- Control/Monad/Sharing.hs | 38 +++++- Control/Monad/Sharing/Classes.hs | 37 +++++- Control/Monad/Sharing/FirstOrder.hs | 29 ----- Control/Monad/Sharing/Implementation/CPS.hs | 55 +++----- .../Sharing/Implementation/FirstOrder.hs | 120 ------------------ .../Monad/Sharing/Implementation/SlowState.hs | 55 -------- .../Sharing/Implementation/SlowStateCPS.hs | 60 --------- Test.hs | 66 ++++++---- explicit-sharing.cabal | 12 +- last.hs | 21 +-- permsort.hs | 20 ++- reverse.hs | 20 +-- 12 files changed, 159 insertions(+), 374 deletions(-) delete mode 100644 Control/Monad/Sharing/FirstOrder.hs delete mode 100644 Control/Monad/Sharing/Implementation/FirstOrder.hs delete mode 100644 Control/Monad/Sharing/Implementation/SlowState.hs delete mode 100644 Control/Monad/Sharing/Implementation/SlowStateCPS.hs diff --git a/Control/Monad/Sharing.hs b/Control/Monad/Sharing.hs index b4914aa..5959283 100644 --- a/Control/Monad/Sharing.hs +++ b/Control/Monad/Sharing.hs @@ -1,3 +1,7 @@ +{-# LANGUAGE RankNTypes, + FlexibleInstances + #-} + -- | -- Module : Control.Monad.Sharing -- Copyright : Chung-chieh Shan, Oleg Kiselyov, and Sebastian Fischer @@ -16,14 +20,40 @@ module Control.Monad.Sharing ( Sharing(..), Shareable(..), Convertible(..), - -- * Monad transformer + -- * Observation functions + + collect, hasResult, results, resultDist, - Lazy, evalLazy, runSharing + resultList, unsafeResults ) where import Control.Monad import Control.Monad.Sharing.Classes import Control.Monad.Sharing.Implementation.CPS --- import Control.Monad.Sharing.Implementation.SlowState --- import Control.Monad.Sharing.Implementation.SlowStateCPS + +import qualified Data.Set as Set +import qualified Data.Map as Map + +hasResult :: (forall s . Sharing s => s a) -> Bool +hasResult a = collect (liftM (const True) a) + +results :: Ord a => (forall s . Sharing s => s a) -> Set.Set a +results a = collect (liftM Set.singleton a) + +resultDist :: Ord a => (forall s . Sharing s => s a) -> Map.Map a Rational +resultDist a = collect (liftM (`Map.singleton`1) a) + +newtype UnsafeResults a = Unsafe { unsafe :: [a] } + +instance Nondet (UnsafeResults a) where + failure = Unsafe [] + + -- does not satisfy required laws + a ? b = Unsafe (unsafe a ++ unsafe b) + +unsafeResults :: (forall s . Sharing s => s a) -> [a] +unsafeResults a = unsafe (collect (liftM (Unsafe . (:[])) a)) + +resultList :: (forall s . Sharing s => s a) -> IO [a] +resultList a = return (unsafeResults a) diff --git a/Control/Monad/Sharing/Classes.hs b/Control/Monad/Sharing/Classes.hs index c9d3c35..a857f3f 100644 --- a/Control/Monad/Sharing/Classes.hs +++ b/Control/Monad/Sharing/Classes.hs @@ -19,21 +19,26 @@ -- sharing. module Control.Monad.Sharing.Classes ( - Sharing(..), Shareable(..), Convertible(..), + Sharing(..), Shareable(..), Convertible(..), Nondet(..), MInt, MChar, MBool ) where +import Control.Monad ( MonadPlus ) + +import qualified Data.Set as Set +import qualified Data.Map as Map + -- | Interface of monads that support explicit sharing. -class Sharing m +class MonadPlus s => Sharing s where -- | -- Yields an action that returns the same results as the given -- action but whose effects are only executed once. Especially, when -- the resulting action is duplicated it returns the same result at -- every occurrence. - share :: Shareable m a => m a -> m (m a) + share :: Shareable s a => s a -> s (s a) -- | -- Interface of shareable nested monadic data types. The provided @@ -185,3 +190,29 @@ instance (Monad m, Convertible m a b) => Convertible m [a] [m b] instance (Monad m, Convertible m a b) => Convertible m [m a] [b] where convert = mapM (>>=convert) + +-- | + +-- Instances of this class can be used to observe non-deterministic +-- computations with sharing. The function '?' must satisfy the +-- following laws: +-- +-- @ +-- a ? a = a +-- (a ? b) ? (c ? d) = (a ? c) ? (b ? d) +-- @ +class Nondet n where + failure :: n + (?) :: n -> n -> n + +instance Nondet Bool where + failure = False + (?) = (||) + +instance Ord a => Nondet (Set.Set a) where + failure = Set.empty + (?) = Set.union + +instance Ord a => Nondet (Map.Map a Rational) where + failure = Map.empty + d1 ? d2 = Map.map (/2) $ Map.unionWith (+) d1 d2 diff --git a/Control/Monad/Sharing/FirstOrder.hs b/Control/Monad/Sharing/FirstOrder.hs deleted file mode 100644 index ccedcc1..0000000 --- a/Control/Monad/Sharing/FirstOrder.hs +++ /dev/null @@ -1,29 +0,0 @@ --- | --- Module : Control.Monad.Sharing.FirstOrder --- Copyright : Chung-chieh Shan, Oleg Kiselyov, and Sebastian Fischer --- License : PublicDomain --- Maintainer : Sebastian Fischer --- Stability : experimental --- --- This library provides an interface to monads that support explicit --- sharing based on two-level types. This implementation is not as --- efficient as the default implementation but supports a restricted --- form of sharing across non-determinism if a first-order data type --- is used as underlying monad. -module Control.Monad.Sharing.FirstOrder ( - - module Control.Monad, - - -- * Classes - - Sharing(..), Shareable(..), Convertible(..), - - -- * Monad transformer - - Lazy, evalLazy - - ) where - -import Control.Monad -import Control.Monad.Sharing.Classes -import Control.Monad.Sharing.Implementation.FirstOrder diff --git a/Control/Monad/Sharing/Implementation/CPS.hs b/Control/Monad/Sharing/Implementation/CPS.hs index cd488db..1d07101 100644 --- a/Control/Monad/Sharing/Implementation/CPS.hs +++ b/Control/Monad/Sharing/Implementation/CPS.hs @@ -19,7 +19,7 @@ -- performance. module Control.Monad.Sharing.Implementation.CPS ( - Lazy, runLazy, evalLazy, runSharing, + collect, Store, emptyStore, freshLabel, lookupValue, storeValue, @@ -29,7 +29,6 @@ module Control.Monad.Sharing.Implementation.CPS ( import Control.Monad ( MonadPlus(..) ) import Control.Monad.State ( MonadState(..), gets, modify ) -import Control.Monad.Trans ( MonadTrans(..), MonadIO(..) ) import Control.Monad.Sharing.Classes @@ -42,32 +41,24 @@ import qualified Data.IntMap as M -- | -- Continuation-based, store-passing implementation of explicit --- sharing. It is an inlined version of @ContT (ReaderT Store m)@ --- where the result type of continuations is polymorphic. -newtype Lazy m a = Lazy { +-- sharing. It is an inlined version of @ContT n (Reader Store)@. +newtype Lazy n a = Lazy { -- | - -- Runs a computation of type @Lazy m a@ with given continuation and + -- Runs a computation of type @Lazy n a@ with given continuation and -- store. - fromLazy :: forall w . (a -> Store -> m w) -> Store -> m w + fromLazy :: (a -> Store -> n) -> Store -> n } -runSharing :: MonadPlus m => (forall s.(MonadPlus s,Sharing s) => s a) -> m a -runSharing a = runLazy a - --- | --- Lifts all monadic effects to the top-level and unwraps the monad --- transformer for explicit sharing. -evalLazy :: (Monad m, Convertible (Lazy m) a b) => Lazy m a -> m b -evalLazy m = runLazy (m >>= convert) -{-# DEPRECATED evalLazy "Please use runSharing instead" #-} +collect :: Nondet n => (forall s. Sharing s => s n) -> n +collect a = runLazy a -- private declarations -runLazy :: Monad m => Lazy m a -> m a -runLazy m = fromLazy m (\a _ -> return a) emptyStore +runLazy :: Nondet n => Lazy n n -> n +runLazy m = fromLazy m (\a _ -> a) emptyStore -- fromLazy m --- (\a s -> trace ("used refs: "++show (nextLabel s-1)) (return a)) +-- (\a s -> trace ("used refs: "++show (nextLabel s-1)) a) -- emptyStore -- Stores consist of a fresh-reference counter and a heap represented @@ -90,36 +81,26 @@ storeValue k v = modify (\s -> s { heap = M.insert k (Untyped v) (heap s) }) -- The monad instance is an inlined version of the instances for -- continuation and reader monads. -instance Monad m => Monad (Lazy m) +instance Nondet n => Monad (Lazy n) where return x = Lazy (\c -> c x) a >>= k = Lazy (\c s -> fromLazy a (\x -> fromLazy (k x) c) s) - fail err = Lazy (\_ _ -> fail err) + fail _ = Lazy (\_ _ -> failure) -- The 'MonadPlus' instance reuses corresponding operations of the --- base monad. -instance MonadPlus m => MonadPlus (Lazy m) +-- underlying 'Nondet' instance. +instance Nondet n => MonadPlus (Lazy n) where - mzero = Lazy (\_ _ -> mzero) - a `mplus` b = Lazy (\c s -> fromLazy a c s `mplus` fromLazy b c s) + mzero = Lazy (\_ _ -> failure) + a `mplus` b = Lazy (\c s -> fromLazy a c s ? fromLazy b c s) -- A Cont/Reader monad is an instance of MonadState -instance Monad m => MonadState Store (Lazy m) +instance Nondet n => MonadState Store (Lazy n) where get = Lazy (\c s -> c s s) put s = Lazy (\c _ -> c () s) --- 'Lazy' is a monad transformer. -instance MonadTrans Lazy - where - lift a = Lazy (\c s -> a >>= flip c s) - --- If the underlying monad supports IO we can lift this functionality. -instance MonadIO m => MonadIO (Lazy m) - where - liftIO = lift . liftIO - -instance Monad m => Sharing (Lazy m) +instance Nondet n => Sharing (Lazy n) where share a = memo (a >>= shareArgs share) diff --git a/Control/Monad/Sharing/Implementation/FirstOrder.hs b/Control/Monad/Sharing/Implementation/FirstOrder.hs deleted file mode 100644 index cf82dcd..0000000 --- a/Control/Monad/Sharing/Implementation/FirstOrder.hs +++ /dev/null @@ -1,120 +0,0 @@ -{-# LANGUAGE ExistentialQuantification, - MultiParamTypeClasses, - FlexibleContexts, - RelaxedPolyRec - #-} - --- | --- Module : Control.Monad.Sharing.Implementation.FirstOrder --- Copyright : Chung-chieh Shan, Oleg Kiselyov, and Sebastian Fischer --- License : PublicDomain --- Maintainer : Sebastian Fischer --- Stability : experimental --- --- Implements a monad transformer for explicit sharing. -module Control.Monad.Sharing.Implementation.FirstOrder ( - - Lazy, evalLazy - - ) where - -import Control.Monad ( MonadPlus(..), liftM ) --- import Control.Monad.State ( MonadState(..), StateT, evalStateT ) -import Control.Monad.Trans ( MonadTrans(..), MonadIO(..) ) - -import Control.Monad.Sharing.Classes - -import qualified Control.Monad.Sharing.Implementation.CPS as CPS -import Control.Monad.Sharing.Implementation.CPS - ( -- Store, emptyStore, - freshLabel, lookupValue, storeValue ) - --- | --- Monad transformer that adds explicit sharing capability to every --- monad. -newtype Lazy m a = Lazy { fromLazy :: m (Labeled m a) } - --- | --- Lifts all monadic effects to the top-level and unwraps the monad --- transformer for explicit sharing. -evalLazy :: (Monad m, Shareable (Lazy m) a, Convertible (Lazy m) a b) - => Lazy m a -> m b -evalLazy m = do Lifted a <- fromLazy (evalS (gnf m) >>= convert) - return a - --- type S m a = StateT Store m a -type S m a = CPS.Lazy m a - -evalS :: Monad m => S m a -> m a --- evalS m = evalStateT m emptyStore -evalS = CPS.runLazy - --- using 'CPS.Lazy' instead of 'StateT Store' is almost twice as fast. - --- private declarations - -data Labeled m a - = Lifted a - | WithFresh (Int -> Lazy m a) - | forall b . Shareable (Lazy m) b => Labeled Int (Lazy m b) (b -> Lazy m a) - - -gnf :: (Monad m, Shareable (Lazy m) a) => Lazy m a -> S (Lazy m) a -gnf a = hnf a >>= shareArgs (liftM return . gnf) - -hnf :: Monad m => Lazy m a -> S (Lazy m) a -hnf m = run =<< lift (lift (fromLazy m)) - -run :: Monad m => Labeled m a -> S (Lazy m) a -run (Lifted a) = return a -run (WithFresh f) = hnf . f =<< freshLabel -run (Labeled n a f) = do thunk <- lookupValue n - case thunk of - Just c -> hnf (f c) - Nothing -> do x <- labelArgs a - storeValue n x - hnf (f x) - -labelArgs :: (Monad m, Shareable (Lazy m) a) => Lazy m a -> S (Lazy m) a -labelArgs a = hnf a >>= shareArgs (\x -> do n <- freshLabel - return (setLabel n x.:a)) - --- some type trickery to identify monads -(.:) :: Lazy m a -> Lazy m b -> Lazy m a -(.:) = const - -setLabel :: (Monad m, Shareable (Lazy m) a) => Int -> Lazy m a -> Lazy m a -setLabel n x = Lazy (return (Labeled n x return)) - -instance Monad m => Monad (Lazy m) - where - return = Lazy . return . Lifted - a >>= k = Lazy (fromLazy a >>= bind k) - fail = Lazy . fail - -bind :: Monad m => (a -> Lazy m b) -> Labeled m a -> m (Labeled m b) -bind k (Lifted a) = fromLazy (k a) -bind k (WithFresh f) = return (WithFresh (\n -> f n >>= k)) -bind k (Labeled n m f) = return (Labeled n m (\x -> f x >>= k)) - --- The 'MonadPlus' instance reuses corresponding operations of the --- base monad. -instance MonadPlus m => MonadPlus (Lazy m) - where - mzero = Lazy mzero - a `mplus` b = Lazy (fromLazy a `mplus` fromLazy b) - --- 'Lazy t' is a monad transformer. -instance MonadTrans Lazy - where - lift = Lazy . liftM Lifted - --- If the underlying monad supports IO we can lift this functionality. -instance MonadIO m => MonadIO (Lazy m) - where - liftIO = lift . liftIO - --- The @Sharing@ instance introduces the internal sharing constructors. -instance Monad m => Sharing (Lazy m) - where - share a = Lazy (return (WithFresh (\n -> return (setLabel n a)))) diff --git a/Control/Monad/Sharing/Implementation/SlowState.hs b/Control/Monad/Sharing/Implementation/SlowState.hs deleted file mode 100644 index bf59e17..0000000 --- a/Control/Monad/Sharing/Implementation/SlowState.hs +++ /dev/null @@ -1,55 +0,0 @@ -{-# LANGUAGE FlexibleContexts, FlexibleInstances #-} - -module Control.Monad.Sharing.Implementation.SlowState ( - - Lazy, evalLazy, - - ThunkStore, Thunk(..), emptyThunks, getFreshKey, lookupThunk, insertThunk - - ) where - -import Data.Maybe ( fromJust ) -import Control.Monad.State - -import qualified Data.IntMap as M - -import Control.Monad.Sharing.Classes -import Control.Monad.Sharing.Implementation.CPS ( Untyped(..), typed ) - -type Lazy m = StateT ThunkStore m - -evalLazy :: (Monad m, Convertible (Lazy m) a b) => Lazy m a -> m b -evalLazy m = evalStateT (m >>= convert) emptyThunks - -instance Monad m => Sharing (StateT ThunkStore m) - where - share a = memo (a >>= shareArgs share) - -memo :: MonadState ThunkStore m => m a -> m (m a) -memo a = do key <- getFreshKey - insertThunk key (Uneval a) - return $ do thunk <- lookupThunk key - case thunk of - Eval x -> return x - Uneval b -> do x <- b - insertThunk key (Eval x) - return x - -data ThunkStore = ThunkStore { nextLabel :: Int, heap :: M.IntMap Untyped } - -data Thunk m a = Uneval (m a) | Eval a - -emptyThunks :: ThunkStore -emptyThunks = ThunkStore 1 M.empty - -getFreshKey :: MonadState ThunkStore m => m Int -getFreshKey = do s <- get - put (s { nextLabel = nextLabel s + 1 }) - return (nextLabel s) - -lookupThunk :: MonadState ThunkStore m => Int -> m (Thunk m a) -lookupThunk k = gets (typed . fromJust . M.lookup k . heap) - -insertThunk :: MonadState ThunkStore m => Int -> a -> m () -insertThunk k v = modify (\s -> s { heap = M.insert k (Untyped v) (heap s) }) - diff --git a/Control/Monad/Sharing/Implementation/SlowStateCPS.hs b/Control/Monad/Sharing/Implementation/SlowStateCPS.hs deleted file mode 100644 index 1125321..0000000 --- a/Control/Monad/Sharing/Implementation/SlowStateCPS.hs +++ /dev/null @@ -1,60 +0,0 @@ -{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, Rank2Types #-} - -module Control.Monad.Sharing.Implementation.SlowStateCPS ( - - Lazy, evalLazy - - ) where - -import Control.Monad.State - -import Control.Monad.Sharing.Classes -import Control.Monad.Sharing.Implementation.SlowState hiding ( Lazy, evalLazy ) - -newtype Lazy m a = Lazy { - fromLazy :: forall w . (a -> ThunkStore -> m w) -> ThunkStore -> m w - } - -evalLazy :: (Monad m, Convertible (Lazy m) a b) => Lazy m a -> m b -evalLazy m = runLazy (m >>= convert) - -runLazy :: Monad m => Lazy m a -> m a -runLazy m = fromLazy m (\a _ -> return a) emptyThunks - -instance Monad m => Monad (Lazy m) - where - return x = Lazy (\c -> c x) - a >>= k = Lazy (\c s -> fromLazy a (\x -> fromLazy (k x) c) s) - fail err = Lazy (\_ _ -> fail err) - -instance MonadPlus m => MonadPlus (Lazy m) - where - mzero = Lazy (\_ _ -> mzero) - a `mplus` b = Lazy (\c s -> fromLazy a c s `mplus` fromLazy b c s) - -instance Monad m => MonadState ThunkStore (Lazy m) - where - get = Lazy (\c s -> c s s) - put s = Lazy (\c _ -> c () s) - -instance MonadTrans Lazy - where - lift a = Lazy (\c s -> a >>= flip c s) - -instance MonadIO m => MonadIO (Lazy m) - where - liftIO = lift . liftIO - -instance Monad m => Sharing (Lazy m) - where - share a = memo (a >>= shareArgs share) - -memo :: MonadState ThunkStore m => m a -> m (m a) -memo a = do key <- getFreshKey - insertThunk key (Uneval a) - return $ do thunk <- lookupThunk key - case thunk of - Eval x -> return x - Uneval b -> do x <- b - insertThunk key (Eval x) - return x diff --git a/Test.hs b/Test.hs index 7c8aa1e..9ad64bd 100644 --- a/Test.hs +++ b/Test.hs @@ -2,8 +2,10 @@ NoMonomorphismRestriction, MultiParamTypeClasses, OverlappingInstances, + IncoherentInstances, FlexibleInstances, - FlexibleContexts + FlexibleContexts, + RankNTypes #-} import Control.Monad.Sharing @@ -46,9 +48,10 @@ 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 res test = zipEq (evalLazy test) res +-- 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 @@ -79,42 +82,47 @@ dup_coin_share = assertEqual [(0,0)::(Int,Int),(1,1)] $ do -- duplicate (const (return 2) (return x)) lazy_share = assertEqual [(2::Int,2::Int)] $ - do x <- share (undefined :: Lazy [] 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)) + dupl (first (return x)) >>= convert heads_share = assertEqual [[0,0::Int],[1,1]] $ do x <- share (cons coin undefined) - dupl (first x) + 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) + 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 :: Lazy [] Int, coin :: Lazy [] Int) + 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 +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 +dupnot_coin = assertEqual [(1::Int,1::Int),(0,0)] $ dupnot coin >>= convert dupnot a = do x <- share a @@ -129,52 +137,54 @@ rep a = do rep_coin = assertEqual [(0::Int,0::Int),(1,1)] $ do Cons x xs <- rep coin - return (x, first xs) + convert (x, first xs) dup_list = assertEqual [([],[]) ,([0::Int],[0::Int]) ,([0,0],[0,0]) ,([0,0,0],[0,0,0])] $ - dup coins + dup coins >>= convert -ignore_shared = assertEqual [(0::Int,1::Int)] $ ign_pair mzero +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 :: Lazy [] Int -> Lazy [] (Lazy [] Int,Lazy [] Int) +ign_pair :: Sharing m => m Int -> m (m Int, m Int) ign_pair a = do - x <- share (a :: Lazy [] Int) + x <- share a return (const (return 0) x, const (return 1) x) -empty_rep = assertEqual [False] $ isEmpty (rep (undefined::Lazy [] Int)) +empty_rep = assertEqual [False] $ isEmpty (rep undef) nest_lazy = assertEqual [42::Int] $ do x <- share (cons (return 42) mzero) - first x :: Lazy [] Int + first x nest_share1 = assertEqual [(0::Int,0::Int),(1,1)] $ do x <- share (share (return True) >> coin) - return (x,x) + convert (x,x) nest_share2 = assertEqual [(0::Int,0::Int),(1,1)] $ do x <- share (share coin >>= id) - return (x,x) + convert (x,x) -dup_dup = assertEqual [((0::Int,0::Int),(0::Int,0::Int)),((1,1),(1,1))] - (dup (dup coin :: Lazy [] (Lazy [] Int,Lazy [] Int)) - :: Lazy [] (Lazy [] (Lazy [] Int,Lazy [] Int), - Lazy [] (Lazy [] Int,Lazy [] Int))) +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 - return ( return (x,y) :: Lazy [] (Lazy [] Int, Lazy [] Int) - , return (x,y) :: Lazy [] (Lazy [] Int, Lazy [] Int)) + 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) +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) \ No newline at end of file + heads (cons coin undefined) >>= convert \ No newline at end of file diff --git a/explicit-sharing.cabal b/explicit-sharing.cabal index a776eee..d26137b 100644 --- a/explicit-sharing.cabal +++ b/explicit-sharing.cabal @@ -1,11 +1,11 @@ Name: explicit-sharing -Version: 0.8 +Version: 0.9 Cabal-Version: >= 1.6 Synopsis: Explicit Sharing of Monadic Effects Description: - This package implements a monad transformer for sharing monadic - effects. + This package implements a monad for non-deterministic computations + with sharing. Category: Control, Monads License: PublicDomain @@ -25,13 +25,9 @@ Library derive >= 2.3.0.1 && < 2.5 Exposed-Modules: Control.Monad.Sharing, Control.Monad.Sharing.Classes, - Control.Monad.Sharing.FirstOrder, Data.Monadic.Derive, Data.Monadic.List - Other-Modules: Control.Monad.Sharing.Implementation.CPS, - Control.Monad.Sharing.Implementation.FirstOrder, - Control.Monad.Sharing.Implementation.SlowState, - Control.Monad.Sharing.Implementation.SlowStateCPS + Other-Modules: Control.Monad.Sharing.Implementation.CPS Ghc-Options: -Wall -fno-warn-name-shadowing Extensions: ExistentialQuantification, MultiParamTypeClasses, diff --git a/last.hs b/last.hs index 169d96c..46a464e 100644 --- a/last.hs +++ b/last.hs @@ -1,19 +1,22 @@ {-# LANGUAGE NoMonomorphismRestriction #-} -- to compile, run: --- ghc -O2 --make last +-- ghc -rtsopts -O2 --make last --- $ time ./last 1000000 +RTS -H1000M -K20M +-- $ time ./last 1000000 +RTS -H2000M -K50M -- True --- user 0m1.154s +-- real 0m2.898s +-- user 0m2.050s --- $ time ./last 10000000 +RTS -H1000M -K20M +-- $ time ./last 10000000 +RTS -H2000M -K50M -- True --- user 0m9.263s +-- real 0m20.585s +-- user 0m19.470s --- $ time ./last.mcc 1000000 +RTS -h1000m -k20m +-- $ time ./last.mcc 1000000 +RTS -h2000m -k50m -- 1000000 --- user 0m6.370s +-- real 0m4.895s +-- user 0m3.960s -- $ time ./last.mcc 10000000 +RTS -h2000m -k50m -- Not enough free memory after garbage collection @@ -26,8 +29,8 @@ import Prelude hiding ( last ) main = do n <- liftM (read.head) getArgs - let result = runSharing(last(convert(replicate n True))>>=convert)::[Bool] - mapM_ print result + result <- resultList (last(convert(replicate n True))>>=convert) + mapM_ print (result :: [Bool]) last :: (MonadPlus m, Sharing m) => m (List m Bool) -> m Bool last l = do x <- share freeBool diff --git a/permsort.hs b/permsort.hs index ef86d88..6035c26 100644 --- a/permsort.hs +++ b/permsort.hs @@ -4,25 +4,21 @@ -- ghc -O2 --make permsort.hs -- $ time ./permsort 20 --- user 0m8.909s +-- real 0m14.049s +-- user 0m13.990s -- time ./permsort.mcc 20 --- user 0m25.067s +-- real 0m13.121s +-- user 0m10.900s --- Comparing different implementations using GHC 6.12.1 +-- Other implementations using GHC 7.0.3 --- standard StateT with unevaluated thunks in store --- user 1m41.645s - --- continition monad with unevaluated thunks in store +-- continuation monad with unevaluated thunks in store -- user 0m37.073s -- continuation monad with fewer store operations -- user 0m29.517s --- additionally with hand optimized memo function --- user 0m8.909s - import Control.Monad.Sharing import Data.Monadic.List @@ -31,8 +27,8 @@ import System ( getArgs ) main = do n <- liftM (read.head) getArgs - let result = runSharing (sort (convert [(1::Int)..n]) >>= convert) :: [[Int]] - mapM_ print result + result <- resultList (sort (convert [(1::Int)..n]) >>= convert) + mapM_ print (result :: [[Int]]) diff --git a/reverse.hs b/reverse.hs index 9566334..6f0c17d 100644 --- a/reverse.hs +++ b/reverse.hs @@ -6,14 +6,17 @@ -- to compile, run: -- ghc -O2 -o reverse.mon --make reverse.hs --- $ time ./reverse.fun 20000 --- user 0m8.804s +-- $ time ./reverse.fun 10000 +-- real 0m1.942s +-- user 0m1.920s --- $ time ./reverse.mon 20000 --- user 0m10.522s +-- $ time ./reverse.mon 10000 +-- real 0m10.774s +-- user 0m10.730s --- $ time ./reverse.mcc 20000 --- user 0m14.530s +-- $ time ./reverse.mcc 10000 +-- real 0m1.945s +-- user 0m1.410s import Control.Monad.Sharing @@ -32,9 +35,8 @@ rev (x:xs) = rev xs ++ [x] main_mon = do n <- liftM (read.head) getArgs - let result = - runSharing(convert=<<(length'=< List m a -> m Int length' Nil = return 0