value-supply (empty) → 0.1
raw patch · 4 files changed
+169/−0 lines, 4 filesdep +basesetup-changed
Dependencies added: base
Files
- Data/Supply.hs +134/−0
- LICENSE +7/−0
- Setup.hs +2/−0
- value-supply.cabal +26/−0
+ Data/Supply.hs view
@@ -0,0 +1,134 @@+--------------------------------------------------------------------+-- |+-- Module : Data.Supply+-- Copyright : (c) Iavor S. Diatchki, 2007+-- License : BSD3+--+-- Maintainer: Iavor S. Diatchki <iavor.diatchki@gmail.com>+-- Stability : provisional+-- Portability: portable+--+-- The technique for generating new values is based on the paper+-- ''On Generating Unique Names''+-- by Lennart Augustsson, Mikael Rittri, and Dan Synek.++module Data.Supply+ (++ -- * Creating supplies+ Supply+ , newSupply+ , newEnumSupply+ , newNumSupply++ -- * Obtaining values from supplies+ , supplyValue++ -- * Generating new supplies from old+ , supplyLeft+ , supplyRight+ , modifySupply+ , split+ , split2+ , split3+ , split4+ ) where++-- Using 'MVar's might be a bit heavy but it ensures that+-- multiple threads that share a supply will get distinct names.+import Control.Concurrent.MVar+import System.IO.Unsafe(unsafePerformIO)++-- Basics ----------------------------------------------------------------------++-- | A type that can be used to generate values on demand.+-- A supply may be turned into two different supplies by using+-- the functions 'supplyLeft' and 'supplyRight'.+data Supply a = Node+ { -- | Get the value of a supply. This function, together with+ -- 'modifySupply' forms a comonad on 'Supply'.+ supplyValue :: a++ -- | Generate a new supply. This supply is different from the one+ -- generated with 'supplyRight'.+ , supplyLeft :: Supply a++ -- | Generate a new supply. This supply is different from the one+ -- generated with 'supplyLeft'.+ , supplyRight :: Supply a+ }++instance Functor Supply where+ fmap f s = modifySupply s (f . supplyValue)++-- | Creates a new supply of values.+-- The arguments specify how to generate values:+-- the first argument is an initial value, the+-- second specifies how to generate a new value from an existing one.+newSupply :: a -> (a -> a) -> IO (Supply a)+newSupply x f = fmap (gen True) (newMVar (iterate f x))++ -- The extra argument to ``gen'' is passed because without+ -- it Hugs spots that the recursive calls are the same but does+ -- not know that unsafePerformIO is unsafe.+ where gen _ r = Node { supplyValue = unsafePerformIO (genSym r),+ supplyLeft = gen False r,+ supplyRight = gen True r }++ genSym :: MVar [a] -> IO a+ genSym r = do a : as <- takeMVar r+ putMVar r as+ return a++-- | Generate a new supply by systematically applying a function+-- to an existing supply. This function, together with 'supplyValue'+-- form a comonad on 'Supply'.+modifySupply :: Supply a -> (Supply a -> b) -> Supply b+modifySupply s f = Node { supplyValue = f s+ , supplyLeft = modifySupply (supplyLeft s) f+ , supplyRight = modifySupply (supplyRight s) f+ }++-- (Supply, supplyValue, modifySupply) form a comonad:+{-+law1 s = [ modifySupply s supplyValue, s ]+law2 s f = [ supplyValue (modifySupply s f), f s ]+law3 s f g = [ (s `modifySupply` f) `modifySupply` g+ , s `modifySupply` \s1 -> g (s1 `modifySupply` f)+ ]+-}+++-- Derived functions -----------------------------------------------------------++-- | A supply of values that are in the 'Enum' class.+-- The initial value is @toEnum 0@, new values are generates with 'succ'.+newEnumSupply :: (Enum a) => IO (Supply a)+newEnumSupply = newSupply (toEnum 0) succ++-- | A supply of values that are in the 'Num' class.+-- The initial value is 0, new values are generated by adding 1.+newNumSupply :: (Num a) => IO (Supply a)+newNumSupply = newSupply 0 (1+)++-- | Generate an infinite list of supplies by using 'supplyLeft' and+-- 'supplyRight' repeatedly.+split :: Supply a -> [Supply a]+split s = supplyLeft s : split (supplyRight s)++-- | Split a supply into two different supplies.+-- The resulting supplies are different from the input supply.+split2 :: Supply a -> (Supply a, Supply a)+split2 s = (supplyLeft s, supplyRight s)++-- | Split a supply into three different supplies.+split3 :: Supply a -> (Supply a, Supply a, Supply a)+split3 s = let s1 : s2 : s3 : _ = split s+ in (s1,s2,s3)++-- | Split a supply into four different supplies.+split4 :: Supply a -> (Supply a, Supply a, Supply a, Supply a)+split4 s = let s1 : s2 : s3 : s4 : _ = split s+ in (s1,s2,s3,s4)++
+ LICENSE view
@@ -0,0 +1,7 @@+Copyright (c) 2006 Iavor S. Diatchki++Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMainWithHooks defaultUserHooks
+ value-supply.cabal view
@@ -0,0 +1,26 @@+Name: value-supply+Version: 0.1+License: BSD3+License-file: LICENSE+Author: Iavor S. Diatchki+Maintainer: iavor.diatchki@gmail.com+Category: Data+Synopsis: A library for generating values without having to thread state.+Description:+ This library can be used to generate values (for example, new names)+ without the need to thread state. This means that functions that+ need to generate new values only need a supply object as an argument,+ and they do not need to return a new supply object as a result.+ This decreases the number of data-dependencies in a program, which+ makes it easier to exploit parallelism.++ The technique for generating new values is based on the paper+ ''On Generating Unique Names''+ by Lennart Augustsson, Mikael Rittri, and Dan Synek.++Build-depends: base+Build-type: Simple+Extra-source-files: LICENSE+Exposed-modules: Data.Supply+GHC-options: -O2 -Wall+