io-memoize (empty) → 1.0.0.0
raw patch · 4 files changed
+167/−0 lines, 4 filesdep +basedep +spawnsetup-changed
Dependencies added: base, spawn
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- io-memoize.cabal +44/−0
- src/System/IO/Memoize.hs +91/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2012, Dan Burton++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 Dan Burton 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,2 @@+import Distribution.Simple+main = defaultMain
+ io-memoize.cabal view
@@ -0,0 +1,44 @@+name: io-memoize+version: 1.0.0.0+synopsis: Memoize IO actions+description:+ Transform an IO action into a similar IO action+ that performs the original action only once.+ .+ You can choose to perform the original action+ in one of three ways:+ .+ (1) lazily (might never be performed)+ .+ (2) eagerly+ .+ (3) concurrently (eager)+ .+ Special thanks to shachaf and headprogrammingczar from #haskell irc+ for helping me reason about the behavior of this library.+++license: BSD3+license-file: LICENSE+author: Dan Burton+maintainer: danburton.email@gmail.com+copyright: (c) 2012 Dan Burton++category: System+build-type: Simple+cabal-version: >=1.8++library+ hs-source-dirs: src+ exposed-modules: System.IO.Memoize+ build-depends: base == 4.*, spawn+ ghc-options: -Wall++source-repository head+ type: git+ location: git://github.com/DanBurton/io-memoize++source-repository this+ type: git+ location: git://github.com/DanBurton/io-memoize+ tag: io-memoize-1.0.0.0
+ src/System/IO/Memoize.hs view
@@ -0,0 +1,91 @@+-- | Memoize IO actions,+-- performing them at most once,+-- but recalling their result for subsequent invocations.+-- This library provides three sequencing strategies:+-- lazy ('ioMemo'), eager ('ioMemo''), and concurrent ('ioMemoPar').+-- +-- The lazy and eager approaches give stronger sequencing guarantees.+-- +-- The following property holds: @join . ioMemo === id@.+-- The same is true for @ioMemo'@ and @ioMemoPar@.+-- +-- Also, for the three memoizers in this library,+-- the memory allocated for the result will not+-- be available for garbage collection until the corresponding+-- memoized action is also available for garbage collection,+-- unless your compiler performs deep magicks.+module System.IO.Memoize (+ ioMemo+ , ioMemo'+ , ioMemoPar+ ) where++import Control.Concurrent.Spawn+import Control.Concurrent.MVar+import Data.IORef++-- | Memoize an IO action.+-- The action will be performed+-- the first time that it its value is demanded;+-- all subsequent invocations+-- will simply recall the value acquired+-- from the first call.+-- If the value is never demanded,+-- then the action will never be performed.+-- +-- This is basically a safe version of+-- 'System.IO.Unsafe.unsafeInterleaveIO'.+-- This function is also thread-safe:+-- it is guaranteed that the action passed in+-- will be performed exactly 0 or 1 times+-- by this code. Exceptions will be propagated+-- to the caller.+-- +-- Example usage:+-- +-- >>> getLine' <- ioMemo getLine+-- +-- >>> replicateM 3 getLine'+-- Hello+-- ["Hello", "Hello", "Hello"]+ioMemo :: IO a -> IO (IO a)+ioMemo action = do+ memo <- newIOMemoizer+ return (memo action)++-- | Memoize an IO action.+-- The action will be performed immediately;+-- all subsequent invocations+-- will recall the value acquired.+ioMemo' :: IO a -> IO (IO a)+ioMemo' action = do+ v <- action+ return (return v)++-- | Memoize an IO action.+-- The action will be performed immediately+-- in a spawned thread.+-- Attempts to access the result+-- will block until the action is finished.+-- +-- This is simply a synonym for 'Control.Concurrent.Spawn.spawn'+ioMemoPar :: IO a -> IO (IO a)+ioMemoPar = spawn++++newIOMemoizer :: IO (IO a -> IO a)+newIOMemoizer = do+ b <- newMVar True+ r <- newIORef undefined+ return (ioMemoizer b r)++ioMemoizer :: MVar Bool -> IORef a -> IO a -> IO a+ioMemoizer b r action = do+ modifyMVar_ b $ \isEmpty ->+ if isEmpty+ then do v <- action+ writeIORef r v+ return False+ else return False+ readIORef r