{- |
Module : <File name or $Header$ to be replaced automatically>
Description : This module implements several kinds of futures using Concurrent Haskell
Maintainer : sabel@ki.cs.uni-frankfurt.de; willig@ki.cs.uni-frankfurt.de
Stability : provisional
Portability : portable
This module implements explicit futures ('EFuture', 'efuture', 'force') as well as several variants of implicit futures
('future', 'recursiveFuture', 'strictFuture', 'strictRecursiveFuture', 'lazyFuture', 'lazyRecursiveFuture')
While explicit futures must be forced (using 'force') if their value is needed, this is not necessary for implicit futures.
For implicit futures it is necessary to put them into the global wrapper 'withFuturesDo'.
-}moduleControl.Concurrent.Futures.Futures(EFuture,efuture,force,future,recursiveFuture,withFuturesDo,strictFuture,strictRecursiveFuture,lazyFuture,lazyRecursiveFuture,hbind,newhandled,bhandle)whereimportControl.ConcurrentimportControl.Exception(evaluate)importSystem.IO.Unsafe--import Data.IO-- | The type 'EFuture' implements explicit futures, i.e. if the value of the future is need it must be forced explicitly using 'force'typeEFuturea=MVara-- | 'efuture' creates an explicit future, i.e. the computation is performed concurrently. The future value can be forced using 'force'efuture::IOa->IO(EFuturea)efutureact=doack<-newEmptyMVarforkIO(act>>=putMVarack)returnack-- | 'force' forces the value of an explicit future ('EFuture'), i.e. the calling thread blocks until the result becomes available.force::EFuturea->IOaforce=takeMVar-- | 'future' creates an implicit future. A non-blocking concurrent computation is started. If the value of the future is needed, then-- the future will be forced implicitly. The concurrent computation is killed if the calling thread stops, even if 'future' is used-- within 'withFuturesDo'.future::IOa->IOafuturecode=doack<-newEmptyMVarthread<-forkIO(code>>=putMVarack)unsafeInterleaveIO(doresult<-takeMVarackkillThreadthreadreturnresult)-- | 'recursiveFuture' behaves similar to 'future' with the difference that the future is recursive, i.e. the future created by-- 'recursiveFuture' is used as argument of the code of the future.recursiveFuture::(a->IOa)->IOarecursiveFuturecode=doack<-newEmptyMVarres<-unsafeInterleaveIO(takeMVarack)thread<-forkIO(coderes>>=putMVarack)unsafeInterleaveIO(dores'<-evaluatereskillThreadthreadreturnres')-- ---------------------------------------------------- not-exported functions for the global manager, they shouldn't be visible outside this module.-- -- The manager is an MVar containing a list of unit-tuplestypeManager=MVar[()]-- creating a new ManagernewManager::IOManagernewManager=newMVar[]-- register a future to a managerregister::a->Manager->IO()registerlman=dolist<-takeMVarmanputMVarman((seql()):list)-- synchronizeMan forces the evaluation of all registered futures synchronizeMan::Manager->IO()synchronizeManman=dolist<-takeMVarmanseqListlistseqList[]=return()seqList(x:xs)=seqx(seqListxs)globalMan=unsafePerformIOnewManager---- ---------------------------------------------------- | 'withFuturesDo' is the global wrapper which should be used around the code involving futures.-- I.e., instead of writing @main=code@ one should use @main=withFuturesDo code@. Note, that there-- should be only one call to 'withFuturesDo' in a program. withFuturesDo::IO()->IO()withFuturesDocode=docodesynchronizeManglobalMan-- | creating a strict future is similar to 'future' with the difference that if used inside 'withFuturesDo'-- it is guaranteed that the concurrent computation is forced (and finished) before the main thread terminates.-- Warning: 'strictFuture' should only be used within the global wrapper 'withFuturesDo'!strictFuture::IOa->IOastrictFuturecode=dofut<-futurecoderegisterfutglobalManreturnfut-- | a recursive variant of 'strictFuture' (see 'recursiveFuture' and 'future)-- Warning: 'strictRecursiveFuture' should only be used within the global wrapper 'withFuturesDo'!strictRecursiveFuture::(a->IOa)->IOastrictRecursiveFuturecode=dofut<-recursiveFuturecoderegisterfutglobalManreturnfut-- | a lazy future. Initially, no concurrent computation is started, but if the lazy future gets (implicitly) forced,-- then the lazy future becomes a strict future.-- Warning: 'lazyFuture' should only be used within the global wrapper 'withFuturesDo'!lazyFuture::IOa->IOalazyFuturecode=unsafeInterleaveIO(strictFuturecode)-- | a recursive variant of 'lazyFuture' (see 'recursiveFuture' and 'future)-- Warning: 'lazyRecursiveFuture' should only be used within the global wrapper 'withFuturesDo'!lazyRecursiveFuture::(a->IOa)->IOalazyRecursiveFuturecode=unsafeInterleaveIO(strictRecursiveFuturecode)-- | a new handle component. bhandle::(a->(a->IO())->t)->IOtbhandlex=dof'<-newEmptyMVarf<-lazyFuture(dov<-takeMVarf'putMVarf'vreturnv)h<-strictFuture(return(\z->(putMVarf'z)))return(xfh)-- | creates a new handle.newhandled::IO(a->IO(),a)newhandled=bhandle(\f->\h->(h,f))-- | binds a handle to its value.hbind::(t->t1)->t->t1hbindhv=hv