packages feed

caf (empty) → 0.0.1

raw patch · 11 files changed

+735/−0 lines, 11 filesdep +basesetup-changed

Dependencies added: base

Files

+ Control/Concurrent/Futures.hs view
@@ -0,0 +1,80 @@+{- |+Module      :  <File name or $Header$ to be replaced automatically>+Description :  This package implements various kinds of concurrency abstractions using futures.+Maintainer  :  mwillig@gmx.de+Stability   :  experimental+Portability :  portable++This package implements futures and various kinds of concurrency abstractions +using futures.++Threads can synchronise their values via futures. +Future values are lazily evaluated so they explicitly suspend the computation. +Each future object is associated with a background thread that computes the future value. +As long as this expression has not been evaluated, the value of the future is unknown. +Whenever an unknown future is accessed the computation will suspend on this future. +Once the value has been evaluated the computation resumes. A handle is a component +that points to an unevaluated future and computes its value on demand.+Therefore, handles are used to associate a value to a future. They provide+a synchronisation mechanism for processes.++Example+This example shows how you can use "Buffer" to concurrently compute the values of +nodes from a binary tree.++> data BTree a = BLeaf a | BNode a (BTree a) (BTree a)++> concSumB :: (Num a) => BTree a -> IO a+> concSumB t = do +>   result <- newBuf+>   case t of+>     BLeaf a -> putBuf result a;+>     BNode a t1 t2 -> sumB result t +>   out <- getBuf result+>   return out++> sumB :: (Num a) => Buffer a -> BTree a -> IO ()+> sumB mvar tree = do +>  case tree of +>    BLeaf a -> putBuf mvar a +>    BNode a t1 t2 -> do+> 			sem <- newBuf+> 			forkIO (sumB sem t1)+> 			forkIO (sumB sem t2)+> 			erg1 <-getBuf sem+> 			erg2 <-getBuf sem +> 			putBuf mvar (erg1 + erg2 + a)++You can test the function with the following test data++> bintree = BNode 1 (BNode 24 (BLeaf 2) (BNode 6 (BLeaf 24) (BLeaf 3)))(BNode 33 (BLeaf 7) (BLeaf 8))+> concSumB bintree++-}+module Control.Concurrent.Futures (+        module Control.Concurrent.Futures.Futures,+	    module Control.Concurrent.Futures.Buffer,+	    module Control.Concurrent.Futures.Chan,+	    module Control.Concurrent.Futures.QSem,+	    module Control.Concurrent.Futures.HQSem,+	    module Control.Concurrent.Futures.BChan,+	    module Control.Concurrent.Futures.Barrier,+	    module Control.Concurrent.Futures.Examples,+ ) where++import Control.Concurrent.Futures.Futures+import Control.Concurrent.Futures.Buffer+import Control.Concurrent.Futures.Chan+import Control.Concurrent.Futures.QSem+import Control.Concurrent.Futures.HQSem+import Control.Concurrent.Futures.BChan+import Control.Concurrent.Futures.Barrier+import Control.Concurrent.Futures.Examples+++-- internal function+--wait :: Bool -> IO Bool+--wait x = do+-- case x of+--  True -> return x+--  otherwise -> return x
+ Control/Concurrent/Futures/BChan.hs view
@@ -0,0 +1,50 @@+{- |+Module      :  <File name or $Header$ to be replaced automatically>+Description :  This module implements a bounded channel concurrency primitive using channels and quantity semaphores+Maintainer  :  mwillig@gmx.de+Stability   :  experimental+Portability :  non-portable (requires Futures)++This modules combines a quantity semaphore from the module Control.Concurrent.Fututes.QSem and a channel from +module  Control.Concurrent.Fututes.Chan to a new synchronisation primitive. Bounded channels have a limited +capacity of storage cells.+Warning: All operations on bounded channels should only be used within the +global wrapper function 'Futures.withFuturesDo'!+-}+module Control.Concurrent.Futures.BChan (+          BChan,+          newBChan,+          readBChan,+          writeBChan++) where+import Control.Concurrent.Futures.Chan+import Control.Concurrent.Futures.QSem++--data BChan a = BChan a (Chan a, QSem )+--type BChanType a = (ChanType a, QSem)++type BChan a = (Chan a, QSem)++-- | Creates a new bounded channel+newBChan :: Int -> IO (BChan a)+newBChan n = do+ chan <- newChan+ qsem <- newQSem n+ return (chan , qsem)++-- | Performs an up-operation on the QSem of the bounded channel and then reads+-- a value from the channel. The read operation may block.+readBChan :: BChan a -> IO a+readBChan (chan, sem) = do+  up sem+  readChan chan++-- | Performs a down-operations on the QSem of the bounded channel and writes a+-- new value to it. The down-operation may block.+writeBChan :: BChan a -> a -> IO ()     +writeBChan (chan, sem) val = do+  down sem+  writeChan chan val+  +              
+ Control/Concurrent/Futures/Buffer.hs view
@@ -0,0 +1,101 @@+{- |+Module      :  <File name or $Header$ to be replaced automatically>+Description :  This module implements a buffer with cells and futures.+Maintainer  :  mwillig@gmx.de+Stability   :  experimental+Portability :  non-portable (requires Futures)++This module implements one-place buffers using futures.+Warning: All operations on buffers should only be used within the global wrapper function+'Futures.withFuturesDo'!+-}+module Control.Concurrent.Futures.Buffer ( + Buffer,+-- Cell,+-- cell,+-- testAndSet,+ wait,+ newBuf,+ putBuf,+ getBuf+) where++import Control.Concurrent.Futures.Futures as Futures+import Control.Concurrent.MVar+import System.IO++-- -- The buffer type contains of 3 cells and a handle.+type Buffer a = (Cell Bool, Cell Bool, Cell a, Cell (Bool -> IO ()))++-----------------------------------------------------------------------+---Cells++-- | A cell type. Cells provide an automic 'exchange' operation.+type Cell a = MVar a++-- | Creates a new cell.+cell :: a -> IO (Cell a)+cell a = newMVar a++exchange :: Cell a -> a -> IO a +exchange a b = swapMVar a b++-- | TestAndSet on cells provides test and set functions in one atomic operation.+testAndSet :: Cell Bool -> IO t -> IO Bool+testAndSet cell code =  do + val <- (exchange cell True)+ case val of+   True -> return True+   False -> do +           code+           exchange cell False++-- | A test on cells+--tsExample = do+-- c <- Buffer.cell False+-- code <- (\x -> do putStrLn "The code." return x)+-- Buffer.testAndSet c code+-- return c+-------------------------------------------------------------------------------++-- | Waits its argument to become true+wait :: Bool -> IO Bool+wait x = do+ case x of+  True -> return x+  otherwise -> return x++-- | Creates a new empty buffer.+newBuf :: IO (Buffer a)+newBuf = do+ (h,f) <- Futures.newhandled+ (h',f') <- Futures.newhandled+ putg <- cell True+ getg <- cell f+ stored <- cell f'+ handler <- cell h+ return (putg,getg,stored,handler)++-- | Puts a new value to a buffer. 'putBuf' blocks if+-- the buffer is full.  +putBuf :: Buffer a -> a -> IO ()+putBuf (putg,getg,stored,handler) val = do+   (h,f) <- Futures.newhandled+   old_value <- exchange putg f+   wait old_value+   exchange stored val+   old_handler <- exchange handler h+   old_handler True++-- | Gets the contents of a non-empty buffer. If the buffer is empty, then +-- this function blocks until the buffer is filled.+getBuf :: Buffer a -> IO a +getBuf (putg,getg,stored,handler) = do+ (h,f) <- Futures.newhandled+ (h',f') <- Futures.newhandled+ old_value <- exchange getg f+ wait old_value+ val <- exchange stored f'+ old_handler <- exchange handler h+ old_handler True+ return val
+ Control/Concurrent/Futures/Chan.hs view
@@ -0,0 +1,106 @@+{- |+Module      :  <File name or $Header$ to be replaced automatically>+Description :  This module implements a channel concurrency primitive using Buffers.+Maintainer  :  mwillig@gmx.de+Stability   :  experimental+Portability :  non-portable (requires Futures)++This module implements a channel synchronisation primitive using buffers that block on+futures. A channel is a linked list of buffers. It has a read-end at one side and a+write-end at the other. Elements put into the channel can be read out in+a first in, first out order. A read and a write operation can be executed in+parallel by several threads. A channel has no capacity bounding.++The module contains similar functions as 'Control.Concurrent.Futures.Chan'.++Warning: All operations on channels should only be used within the global wrapper function+'Futures.withFuturesDo'!+-}+module Control.Concurrent.Futures.Chan (+             Chan,+             ChanType,+           	 newChan,+             writeChan,+             readChan,+             writeChanContents,+             getChanContents,+             mergeChan+  ) where+  +-- qualified, because channel functions are also defined in +-- Control.Concurrent+import qualified Control.Concurrent+import System.IO.Unsafe		( unsafeInterleaveIO )+import Control.Concurrent.Futures.Buffer+import Control.Concurrent.Futures.Futures++-- | A channel consists of a read-end buffer and a write-end buffer. +-- The Itemtype is required to link the buffers in the channel.+data Chan a+	 = Chan (Buffer (ItemType a))+	        (Buffer (ItemType a))++type ChanType a = ((Buffer (ItemType a)), (Buffer (ItemType a)))+type ItemType a = (Buffer(Item a))        +data Item a = Item a (ItemType a)++-- | Creates a new empty channel.               +newChan :: IO (Chan a)+newChan = do+ hole <- newBuf+ read_end <- newBuf+ write_end <- newBuf+ putBuf read_end hole+ putBuf write_end hole+ return (Chan read_end write_end)+ +-- | Writes one value to a channel. A 'writeChan' never blocks, since channels have +-- no bounding limiters.+writeChan :: Chan a -> a -> IO ()+writeChan (Chan read_end write_end) val = do+ new_hole <- newBuf+ old_hole <- getBuf write_end+ putBuf write_end new_hole+ putBuf old_hole (Item val new_hole)++  +-- | Reads out an item from the read-head of the channel.+-- It blocks on a empty channel.+readChan :: Chan a -> IO a+readChan (Chan read_end write_end) = do+  chan_head <- getBuf read_end+  (Item val content) <- getBuf chan_head+  putBuf read_end content+  return val+++-- | Implements the same behaviour as writeChanContents from the module Control.Concurrent.Chan.+writeChanContents :: Chan a -> [a] -> IO ()+writeChanContents chan (x:xs) = do+ Control.Concurrent.forkIO (writeChan chan x)+ writeChanContents chan xs+ >>= return+writeChanContents chan [] = return ()++-- | Implements the same behaviour as getChanContents from the module Control.Concurrent.Chan.+-- It reads permanently from the channel.+getChanContents :: Chan a -> IO [a]+getChanContents ch+  = unsafeInterleaveIO ( do+    x  <- readChan ch+    xs <- getChanContents ch+    return (x:xs)+    )++-- | Writes two equally typed lists to a given channel in parallel.+mergeChan :: [a] -> [a] -> Chan a -> IO (Chan a)+mergeChan l1 l2 cm = do+          	Control.Concurrent.forkIO (merge l1 cm)+          	Control.Concurrent.forkIO (merge l2 cm)+          	return cm++-- internal function     +merge (x:xs) c = do+ Control.Concurrent.forkIO (writeChan c x)+ (merge xs c)+merge [] c = return ()
+ Control/Concurrent/Futures/Futures.hs view
@@ -0,0 +1,155 @@+{- |+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+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'.+-}++module Control.Concurrent.Futures.Futures (+             EFuture,+             efuture,+             force,+             future,+             recursiveFuture,+             withFuturesDo,+             strictFuture,+             strictRecursiveFuture,+             lazyFuture,+             lazyRecursiveFuture,+             hbind,+             newhandled,+             bhandle+  ) where+import Control.Concurrent+import Control.Exception(evaluate)+import System.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'+type EFuture a = MVar a++-- | 'efuture' creates an explicit future, i.e. the computation is performed concurrently. The future value can be forced using 'force'+efuture :: IO a -> IO (EFuture a)+efuture act = + do  ack <- newEmptyMVar+     forkIO (act >>= putMVar ack)+     return ack++-- | 'force' forces the value of an explicit future ('EFuture'), i.e. the calling thread blocks until the result becomes available.+force :: EFuture a -> IO a+force = 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 :: IO a -> IO a    +future code = do ack <-newEmptyMVar+                 thread <- forkIO (code >>= putMVar ack)+                 unsafeInterleaveIO (do result <- takeMVar ack+                                        killThread thread+                                        return result)++-- | '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 -> IO a) -> IO a    +recursiveFuture code = do ack <- newEmptyMVar+                          res <- unsafeInterleaveIO (takeMVar ack)+                          thread <- forkIO (code res >>= putMVar ack)+                          unsafeInterleaveIO (do res' <- evaluate res+                                                 killThread thread+                                                 return res')++-- --------------------------------------------------+-- 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-tuples+type Manager = MVar [()]++-- creating a new Manager+newManager :: IO Manager+newManager = newMVar []++-- register a future to a manager+register :: a -> Manager -> IO ()+register  l man =  do+                     list <- takeMVar man+                     putMVar man ((seq l ()):list)++-- synchronizeMan forces the evaluation of all registered futures +synchronizeMan :: Manager -> IO ()+synchronizeMan man = do +                      list <- takeMVar man+                      seqList list++seqList []     = return ()+seqList (x:xs) = seq x (seqList xs)+++globalMan = unsafePerformIO newManager++--+-- --------------------------------------------------++-- | '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 ()+withFuturesDo code =  do code   +                         synchronizeMan globalMan+++-- | 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 :: IO a -> IO a+strictFuture code = do fut <- future code+                       register fut globalMan+                       return fut++-- | a recursive variant of 'strictFuture' (see 'recursiveFuture' and 'future)+-- Warning: 'strictRecursiveFuture' should only be used within the global wrapper 'withFuturesDo'!+strictRecursiveFuture :: (a -> IO a) -> IO a    +strictRecursiveFuture code = do fut <- recursiveFuture code+                                register fut globalMan+                                return fut++-- | 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 :: IO a -> IO a     +lazyFuture code = unsafeInterleaveIO (strictFuture code)++-- | a recursive variant of 'lazyFuture' (see 'recursiveFuture' and 'future)+-- Warning: 'lazyRecursiveFuture' should only be used within the global wrapper 'withFuturesDo'!+lazyRecursiveFuture :: (a -> IO a) -> IO a     +lazyRecursiveFuture code = unsafeInterleaveIO (strictRecursiveFuture code)++-- | a new handle component. +bhandle :: (a -> (a -> IO ()) -> t) -> IO t+bhandle x = do +             f' <- newEmptyMVar+             f  <- lazyFuture  (do +                                 v <- takeMVar f'+                                 putMVar f' v+                                 return v+                               )+             h <- strictFuture (return (\z -> (putMVar f' z)))+             return (x f h)+             +-- | 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 -> t1+hbind h v = h v
+ Control/Concurrent/Futures/HQSem.hs view
@@ -0,0 +1,67 @@+{- |+Module      :  <File name or $Header$ to be replaced automatically>+Description :  This module implements a quantity semaphores with handles+Maintainer  :  mwillig@gmx.de+Stability   :  experimental+Portability :  non-portable (requires Futures)++This module implements a quantity semaphore using handles that block on+futures.+A HQSem equals to QSemN in Control.Concurrent.+A Buffer euqals to QSem in Control.Concurrent.+Warning: All operations on quantity semaphores should only be used within the +global wrapper function 'Futures.withFuturesDo'!+-}+module Control.Concurrent.Futures.HQSem (+            HQSem,+			newHQSem,+			upHQSem,+			downHQSem+) where++import qualified Control.Concurrent+import System.IO.Unsafe		( unsafeInterleaveIO )+import Control.Concurrent.Futures.Futures as Futures+import Control.Concurrent.Futures.Buffer++-- | A handled quantity semaphores contains of a capacity and a waiting queue containing +-- handles.+type HQSem = Buffer (Int, [Bool -> IO ()])++-- | Creates a new quantity semaphore of capacity cnt.+newHQSem :: Int -> IO (HQSem)+newHQSem cnt = do+ b <- newBuf+ putBuf b (cnt,[])+ return b+  ++-- | Increments the semaphore's value, if there are no waiters.+-- 'up' reads out of the waiting queue and binds a waiting handle to True.+-- Note: This operation equals to signalQSemN in Control.Concurrent.QSemN.+upHQSem :: HQSem -> IO ()+upHQSem qsem = do+ b <- getBuf qsem+ case b of+   (cnt,ls) -> case ls of+     [] -> do putBuf qsem (cnt+1,ls)+     x:xs -> do+       x True+       putBuf qsem (cnt,ls)++-- | Decrements the semaphore's value. If the value has already reached 0, then +-- 'down' creates a new handle that is being added to the semaphore's waiting queue.+-- It blocks until the handle assigns a value to its future by a 'up'.+-- Note: This operation equals to waitQSemN in Control.Concurrent.QSemN.+downHQSem :: HQSem -> IO (Bool)+downHQSem qsem = do+ b <-getBuf qsem+ case b of+     (cnt,ls) -> case (cnt==0) of+	    True -> do+	      (h,f) <- Futures.newhandled+	      putBuf qsem (cnt,h:ls)+	      (wait f)+	    False -> do+	      putBuf qsem (cnt-1,ls)+	      return True
+ Control/Concurrent/Futures/QSem.hs view
@@ -0,0 +1,86 @@+{- |+Module      :  <File name or $Header$ to be replaced automatically>+Description :  This module implements a quantity semaphores with buffers+Maintainer  :  mwillig@gmx.de+Stability   :  experimental+Portability :  non-portable (requires Futures)++This module implements a quantity semaphore using buffers that block on+futures.++A QSem equals to QSemN in Control.Concurrent.+A Buffer equals to QSem in Control.Concurrent.++Warning: All operations on quantity semaphores should only be used within the +global wrapper function 'Futures.withFuturesDo'!+-}+module Control.Concurrent.Futures.QSem (+            QSem,+			newQSem,+			up,+			down,+			enter+) where++import qualified Control.Concurrent+import System.IO.Unsafe		( unsafeInterleaveIO )+import Control.Concurrent.Futures.Futures+import Control.Concurrent.Futures.Buffer++-- | A quantity semaphores contains of a capacity and a waiting queue containing +-- buffers.+type QSem = Buffer (Int, [Buffer Bool])++-- | Creates a new quantity semaphore of capacity cnt.+newQSem :: Int -> IO (Buffer (Int, [Buffer Bool]))+newQSem cnt = do+ b <- newBuf+ putBuf b (cnt,[])+ return b+ -- For comparison the implementation of the Concurrent Haskell Library +--newQSem :: Int -> IO QSem+--newQSem init = do+--sem <- newMVar (init,[])+--return (QSem sem)+++-- | Increments the semaphore's value, if there are no waiters.+-- 'up' reads out of the waiting queue and writes True into a waiting 'Buffer'.+-- Note: This operation equals to signalQSemN in Control.Concurrent.QSemN.+up :: QSem -> IO ()+up qsem = do+ (cnt,ls) <- getBuf qsem+ case ls of+          [] -> do putBuf qsem (cnt+1,ls)+          x:xs -> do+            putBuf x True+            putBuf qsem (cnt,ls)++-- | Decrements the semaphore's value. If the value has already reached zero, then +-- 'down' creates a new empty 'Buffer' that is being added to the semaphore's waiting queue.+-- It blocks until the buffer gets filled by a 'up'.+-- Note: This operation equals to waitQSemN in Control.Concurrent.QSemN.+down :: QSem -> IO Bool+down qsem = do+ b <-getBuf qsem+ case b of+     (cnt,ls) -> case (cnt==0) of+         True -> do+           b1 <- newBuf+           putBuf qsem (cnt,b1:ls)+           getBuf b1+         False -> do+           putBuf qsem (cnt-1,ls)+           return True++-- | Use the quantity semaphore to limit the computation of code. This function+-- performs a down on the given q. s., executues the code and returns after a up+-- on the q.s. .+enter :: QSem -> IO a -> IO ()+enter qsem code = do+ x <- down qsem+ case x of+  True -> do+   code +   up qsem+  False -> return ()
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright 2009, Martina Willig <willig@ki.informatik.uni-frankfurt.de>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+   notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+   notice, this list of conditions and the following disclaimer in the+   documentation and/or other materials provided with the distribution.+3. Neither the name of the author nor the names of his contributors+   may be used to endorse or promote products derived from this software+   without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.
+ README view
@@ -0,0 +1,35 @@+Concurrency Abstractions with Futures+======================================+More info on the package, releases, etc. can be found at
+
+  http://haskell.forkIO.com/dotnet+  +--------------------------------------+Install distribution package+--------------------------------------+1. Unzip the tarball+2. Navigate to the directory+3. Run the installation commands+  runhaskell Setup configure+  runhaskell Setup build+  sudo runhaskell Setup install++This last step will register thedistribution package.+Now in your Haskell programs, you can simply import the new modules from the distribution package.++--------------------------------------+Uninstall distribution package+--------------------------------------+See a list of installed packages with this command+	ghc-pkg list++Unregister the package with+	ghc-pkg unregister caf-x.x++--------------------------------------+Feedback+--------------------------------------+Please send Feedback to ++willig@ki.informatik.uni-frankfurt.de
+
+ Setup.hs view
@@ -0,0 +1,4 @@+-- file: ch05/Setup.hs+#!/usr/bin/env runhaskell+import Distribution.Simple+main = defaultMain
+ caf.cabal view
@@ -0,0 +1,24 @@+Name:                caf+Version:             0.0.1+Description:         This library contains implementations of several kinds of futures and concurrency abstractions.+License:             BSD3+License-file:        LICENSE+Author:              Dr. David Sabel and Martina Willig +Maintainer:          Martina Willig <willig@ki.informatik.uni-frankfurt.de>+Build-Type:          Simple+Stability:           experimental+Synopsis:            A library of Concurrency Abstractions using Futures.+Category:            Concurrency+Cabal-Version:       >= 1.2+Extra-Source-Files:  README+library+  Exposed-Modules: Control.Concurrent.Futures+                   Control.Concurrent.Futures.Futures+                   Control.Concurrent.Futures.Buffer+                   Control.Concurrent.Futures.Chan+                   Control.Concurrent.Futures.QSem+                   Control.Concurrent.Futures.BChan+                   Control.Concurrent.Futures.HQSem+  Build-Depends:   base >= 2.0++