abstract-par (empty) → 0.3
raw patch · 5 files changed
+296/−0 lines, 5 filesdep +basedep +deepseqsetup-changed
Dependencies added: base, deepseq
Files
- Control/Monad/Par/Class.hs +173/−0
- Control/Monad/Par/Unsafe.hs +36/−0
- LICENSE +30/−0
- Setup.hs +3/−0
- abstract-par.cabal +54/−0
+ Control/Monad/Par/Class.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, CPP,+ FlexibleInstances, UndecidableInstances+ #-}+-- UndecidableInstances++{-|++ This module establishes a class hierarchy that captures the+ interface(s) for valid Par monads. In particular, the functionality+ is split into layers: e.g. Futures vs. full IVars vs. Chans (Streams). + + Not all Par monad schedulers must provide all functionality.++ For more documentation of the programming model, see ++ * The "Control.Monad.Par" module in the @monad-par@ package.+ * The wiki/tutorial (<http://www.haskell.org/haskellwiki/Par_Monad:_A_Parallelism_Tutorial>)+ * The original paper (<http://www.cs.indiana.edu/~rrnewton/papers/haskell2011_monad-par.pdf>)+ * Tutorial slides (<http://community.haskell.org/~simonmar/slides/CUFP.pdf>)+ * Other slides: <http://www.cs.ox.ac.uk/ralf.hinze/WG2.8/28/slides/simon.pdf>, + <http://www.cs.indiana.edu/~rrnewton/talks/2011_HaskellSymposium_ParMonad.pdf>++ -}+-- ++module Control.Monad.Par.Class + ( + -- * Futures+ ParFuture(..)+ -- * IVars+ , ParIVar(..)+ + -- RRN: Not releasing this interface until there is a nice implementation of it:+ -- Channels (Streams)+ -- , ParChan(..)++ , NFData()+ )+where++import Control.DeepSeq++--------------------------------------------------------------------------------++-- | @ParFuture@ captures the class of Par monads which support+-- futures. This level of functionality subsumes @par@/@pseq@ and is+-- similar to the "Control.Parallel.Strategies.Eval" monad.+-- +-- A minimal implementation consists of `spawn_` and `get`.+-- However, for monads that are also a member of `ParIVar` it is+-- typical to simply define `spawn` in terms of `fork`, `new`, and `put`.+class Monad m => ParFuture future m | m -> future where+ -- | Create a potentially-parallel computation, and return a /future/+ -- (or /promise/) that can be used to query the result of the forked+ -- computataion. + --+ -- > spawn p = do+ -- > r <- new+ -- > fork (p >>= put r)+ -- > return r+ --+ spawn :: NFData a => m a -> m (future a)+ + -- | Like 'spawn', but the result is only head-strict, not fully-strict.+ spawn_ :: m a -> m (future a)+ get :: future a -> m a++ -- | Spawn a pure (rather than monadic) computation. Fully-strict.+ -- + -- > spawnP = spawn . return+ spawnP :: NFData a => a -> m (future a)+ + -- Default implementations:+ spawn p = spawn_ (do x <- p; deepseq x (return x))+ spawnP a = spawn (return a)+++--------------------------------------------------------------------------------++-- | @ParIVar@ builds on futures by adding full /anyone-writes, anyone-reads/ IVars.+-- These are more expressive but may not be supported by all distributed schedulers.+-- +-- A minimal implementation consists of `fork`, `put_`, and `new`.+class ParFuture ivar m => ParIVar ivar m | m -> ivar where+ -- | Forks a computation to happen in parallel. The forked+ -- computation may exchange values with other computations using+ -- @IVar@s.+ fork :: m () -> m ()+ + -- | creates a new @IVar@+ new :: m (ivar a)+ + -- | put a value into a @IVar@. Multiple 'put's to the same @IVar@+ -- are not allowed, and result in a runtime error.+ --+ -- 'put' fully evaluates its argument, which therefore must be an+ -- instance of 'NFData'. The idea is that this forces the work to+ -- happen when we expect it, rather than being passed to the consumer+ -- of the @IVar@ and performed later, which often results in less+ -- parallelism than expected.+ --+ -- Sometimes partial strictness is more appropriate: see 'put_'.+ --+ put :: NFData a => ivar a -> a -> m ()+ put v a = deepseq a (put_ v a)+ + -- | like 'put', but only head-strict rather than fully-strict. + put_ :: ivar a -> a -> m ()++ -- Extra API routines that have default implementations:+ + -- | creates a new @IVar@ that contains a value+ newFull :: NFData a => a -> m (ivar a)+ newFull a = deepseq a (newFull_ a)+ + -- | creates a new @IVar@ that contains a value (head-strict only)+ newFull_ :: a -> m (ivar a)+ newFull_ a = do v <- new+ -- This is usually inefficient! + put_ v a+ return v++-------------------------------------------------------------------------------- ++-- class ParYieldable ?? + -- TODO: I think we should add yield officially:++ -- Allows other parallel computations to progress. (should not be+ -- necessary in most cases).+ -- yield :: m ()+++--------------------------------------------------------------------------------++-- | @ParChan@ provides communication via streams of values between+-- computations in a Par monad. Channels in this case are split+-- into separate send and receive ports.+--+-- The critical thing to know about @Chan@s in @Par@ monads is that+-- while the @recv@ method destructively advances the position of+-- the consumer's \"cursor\" in the stream, this is only observable+-- in the /local/ @Par@ thread. That is, at @fork@ points it is+-- necessary to give the child computation a separate set of stream+-- cursors so that it observes the same sequences as the parent.+class Monad m => ParChan snd rcv m | m -> snd, m -> rcv where+ -- | Create a new communication channel, with separate send and receive ports.+ newChan :: m (snd a, rcv a)+ -- | Receive a message on a channel in a synchronous, blocking manner.+ recv :: rcv a -> m a+ -- | Send a message on a channel. This may or may not block.+ send :: snd a -> a -> m ()+++----------------------------------------------------------------------------------------------------++-- t1 :: P.Par Int+-- If the ParIVar => ParFuture instance exists the following is sufficient:+t1 :: (ParFuture v m) => m Int+t1 = do + x <- spawn (return 3)+ get x++t2 :: (ParIVar v m) => m Int+t2 = do + x <- new+ put x "hi"+ return 3+++-- TODO: SPECIALIZE generic routines for the default par monad (and possibly ParRNG)?++-- SPECIALISE parMap :: (NFData b) => (a -> b) -> [a] -> Par [b] +-- SPECIALISE parMapM :: (NFData b) => (a -> Par b) -> [a] -> Par [b]
+ Control/Monad/Par/Unsafe.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}+-- TODO: ADD Unsafe++-- | Unsafe operations. NOT part of "Safe Haskell".+-- +-- These are "unsafe" (in the normal, Haskell sense) when used with a+-- "runPar" of type `Par a -> a`. If used with a `runParIO` that+-- stays in the IO monad, then they are simply dangerous.+-- +-- For the purposes of Safe Haskell, any module that imports this+-- module becomes untrustworthy.++module Control.Monad.Par.Unsafe + (+ ParUnsafe(..)+ ) +where++-- import Control.Monad.Par.Class++-- | The class of Par monads that provide unsafe functionality.+class ParUnsafe iv p | p -> iv where + -- | Peek at the current contents of an 'IVar' in a nonblocking way.+ unsafePeek :: iv a -> p (Maybe a)++ -- | Attempt to put a value into an 'IVar'. If successful, return the+ -- value put. If something is already there, return it instead.+ unsafeTryPut :: iv a -> a -> p a++ -- | Lift an 'IO' operation into the Par monad.+ unsafeParIO :: IO a -> p a++-- Aside:+-- If the need ever arises we could also consider unsafeMultiplePut that+-- would be able to change the current value of an IVar. It could+-- cause big problems in the distributed case, however.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Simon Marlow 2011++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * 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.++ * Neither the name of Simon Marlow nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"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 COPYRIGHT+OWNER 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.
+ Setup.hs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+import Distribution.Simple+main = defaultMain
+ abstract-par.cabal view
@@ -0,0 +1,54 @@+Name: abstract-par+Version: 0.3+Synopsis: Type classes generalizing the functionality of the 'monad-par' library.+++-- Version history:++-- 0.3 : Factored out of monad-par package.+++Description: The 'Par' monad(s) offer an alternative + parallel programming API to that provided by the + @parallel@ package.++ A 'Par' monad allows the simple description of+ parallel computations, and can be used to add+ parallelism to pure Haskell code. The basic API+ is straightforward: a @Par@ monad supports forking+ and simple communication in terms of 'IVar's.++ This module is an interface module only. It+ provides a number of type clasess, but not an+ implementation. The type classes separate different + levels of @Par@ functionality. See the + "Control.Monad.Par.Class" module for more details.++ The 'monad-par' library is one example of a+ concrete library providing this interface.+++Homepage: https://github.com/simonmar/monad-par+License: BSD3+License-file: LICENSE+Author: Ryan Newton+Maintainer: Ryan Newton <rrnewton@gmail.com>+Copyright: (c) Ryan Newton 2011-2012+Stability: Experimental+Category: Control,Parallelism,Monads+Build-type: Simple+Cabal-version: >=1.8++extra-source-files:+++Library+ Exposed-modules: + -- A class generalizing different levels of monad-par functionality:+ Control.Monad.Par.Class++ -- A class providing unsafe functionality:+ , Control.Monad.Par.Unsafe++ Build-depends: base >= 4 && < 5+ , deepseq >= 1.2