strict-io (empty) → 0.1
raw patch · 6 files changed
+484/−0 lines, 6 filesdep +basedep +extensible-exceptionsdep +parallelsetup-changed
Dependencies added: base, extensible-exceptions, parallel
Files
- Data/IORef/Strict.hs +68/−0
- LICENSE +28/−0
- Setup.lhs +3/−0
- System/IO/Strict.hs +253/−0
- System/IO/Strict/Internals.hs +100/−0
- strict-io.cabal +32/−0
+ Data/IORef/Strict.hs view
@@ -0,0 +1,68 @@+--------------------------------------------------------------------+-- |+-- Module : Data.IORef.Strict+-- Copyright : (c) Nicolas Pouillard 2009+-- License : BSD3+--+-- Maintainer : Nicolas Pouillard <nicolas.pouillard@gmail.com>+-- Stability : provisional+--+-- Mutable references of strict values in the 'SIO' monad.+--+-- The type of references remains the same as in the 'IO' monad+-- and is just re-exported here.+--------------------------------------------------------------------++module Data.IORef.Strict+ (IORef+ ,newIORef+ ,readIORef+ ,writeIORef+ ,modifyIORef+ ,atomicModifyIORef+ ,mkWeakIORef+ )+where++import qualified System.IO.Strict.Internals as SIO+import System.IO.Strict.Internals (SIO(..))+import System.Mem.Weak (Weak)+import qualified Data.IORef as IO+import Data.IORef (IORef)+import Control.Parallel.Strategies (NFData(..))++-- | Build a new 'IORef', but force the value before storing it.+newIORef :: NFData sa => sa -> SIO (IORef sa)+newIORef value = rnf value `seq` SIO (IO.newIORef value)++-- | Read the value of an 'IORef'+readIORef :: IORef a -> SIO a+readIORef = SIO . IO.readIORef++-- | Deeply force a value and write it into an 'IORef'+writeIORef :: NFData sa => IORef sa -> sa -> SIO ()+writeIORef ref value = rnf value `seq` SIO $ IO.writeIORef ref value++-- | Mutate the contents of an 'IORef'+modifyIORef :: NFData sa => IORef sa -> (sa -> sa) -> SIO ()+modifyIORef ref f = readIORef ref >>= writeIORef ref . f++-- | Atomically modifies the contents of an 'IORef'.+--+-- This function is useful for using 'IORef' in a safe way in a multithreaded program.+-- If you only have one 'IORef', then using 'atomicModifyIORef' to access and modify+-- it will prevent race conditions.+--+-- Extending the atomicity to multiple 'IORef's is problematic, so it is recommended that+-- if you need to do anything more complicated then using "Control.Concurrent.MVar.MVar"+-- instead is a good idea.+atomicModifyIORef :: (NFData sa, NFData sb) => IORef sa -> (sa -> (sa, sb)) -> SIO sb+atomicModifyIORef ref f = SIO $ do x <- IO.atomicModifyIORef ref (rnf' . f)+ rnf x `seq` return x+ -- since the result of 'f' is a pair which has to forced + where rnf' x = rnf x `seq` x++-- | Make a 'Weak' pointer to an 'IORef'+mkWeakIORef :: IORef a -> SIO () -> SIO (Weak (IORef a))+mkWeakIORef ref (SIO finalizer) = SIO $ IO.mkWeakIORef ref finalizer+
+ LICENSE view
@@ -0,0 +1,28 @@+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.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ System/IO/Strict.hs view
@@ -0,0 +1,253 @@+--------------------------------------------------------------------+-- |+-- Module : System.IO.Strict+-- Copyright : (c) Nicolas Pouillard 2009+-- License : BSD3+--+-- Maintainer : Nicolas Pouillard <nicolas.pouillard@gmail.com>+-- Stability : provisional+--+-- This module wraps the functions of the "System.IO" module at a different type namely 'SIO'.+--+-- The purpose of this module is to export only strict /IO/ functions, by strict+-- we mean strict in the result. The arguments of these functions may only by partially forced,+-- but when the function returns, the arguments can no longer be forced by the function.+-- When the type of the value to be forced is polymorphic, a 'NFData' constraint is added+-- since we (internally) use 'rnf' to force the value. Then we rely on the behavior+-- of 'NFData' instances to provide the fact that any lazy argument passed to a 'SIO' function+-- will not leak-out after the call.+--+-- These functions do not necessarily use their arguments completely but they do not hold+-- or return any value that could depend on these arguments. If the original functions +-- from "System.IO" module were already strict, then this module just provides them+-- at another type.+-- Some functions from the original module are famously lazy like the 'getContents' like+-- functions: in this module their results are deeply forced.+--+-- In Haskell, monad operations ('return' and '>>=') have to be lazy. Therefore the 'SIO'+-- monad is not completely strict (i.e. pure values can still be lazy). So in this module we+-- expose the 'return'' function that forces the given value before putting it into the monad.+--+-- Since this module uses the same names as "System.IO", it is designed to be imported /qualified/.+--+-- @+-- import System.IO.Strict (SIO)+-- import qualified System.IO.Strict as SIO+-- @+--------------------------------------------------------------------+module System.IO.Strict+(+ -- * Types+ SIO,+ run,+ return',+ + -- * Functions stricter than there "System.IO" counterparts+ getContents, -- :: SIO String+ hGetContents, -- :: Handle -> SIO String+ readFile, -- :: FilePath -> SIO String+ read, -- :: (NFData sa, Read sa) => String -> SIO sa+ readLn, -- :: (NFData sa, Read sa) => SIO sa+ fix, -- :: NFData sa => (sa -> SIO sa) -> SIO sa+ withBinaryFile, -- :: NFData sr => FilePath -> IOMode -> (Handle -> SIO sr) -> SIO sr+ withFile, -- :: NFData sr => FilePath -> IOMode -> (Handle -> SIO sr) -> SIO sr++ -- * Functions as strict as there "System.IO" counterparts+ appendFile, -- :: FilePath -> String -> SIO ()+ getChar, -- :: SIO Char+ getLine, -- :: SIO String+ hPrint, -- :: (Show a) => Handle -> a -> SIO ()+ hPutStrLn, -- :: Handle -> String -> SIO ()+ hReady, -- :: Handle -> SIO Bool+ interact, -- :: (String -> String) -> SIO ()+ openBinaryTempFile, -- :: FilePath -> String -> SIO (FilePath, Handle)+ openTempFile, -- :: FilePath -> String -> SIO (FilePath, Handle)+ print, -- :: (Show a) => a -> SIO ()+ putChar, -- :: Char -> SIO ()+ putStr, -- :: String -> SIO ()+ putStrLn, -- :: String -> SIO ()+ writeFile, -- :: FilePath -> String -> SIO ()+ hClose, -- :: Handle -> SIO ()+ hFileSize, -- :: Handle -> SIO Integer+ hFlush, -- :: Handle -> SIO ()+ hGetBuf, -- :: Handle -> Ptr a -> Int -> SIO Int+ hGetBufNonBlocking, -- :: Handle -> Ptr a -> Int -> SIO Int+ hGetBuffering, -- :: Handle -> SIO BufferMode+ hGetChar, -- :: Handle -> SIO Char+ hGetEcho, -- :: Handle -> SIO Bool+ hGetLine, -- :: Handle -> SIO String+ hGetPosn, -- :: Handle -> SIO HandlePosn+ hIsClosed, -- :: Handle -> SIO Bool+ hIsEOF, -- :: Handle -> SIO Bool+ hIsOpen, -- :: Handle -> SIO Bool+ hIsReadable, -- :: Handle -> SIO Bool+ hIsSeekable, -- :: Handle -> SIO Bool+ hIsTerminalDevice, -- :: Handle -> SIO Bool+ hIsWritable, -- :: Handle -> SIO Bool+ hLookAhead, -- :: Handle -> SIO Char+ hPutBuf, -- :: Handle -> Ptr a -> Int -> SIO ()+ hPutBufNonBlocking, -- :: Handle -> Ptr a -> Int -> SIO Int+ hPutChar, -- :: Handle -> Char -> SIO ()+ hPutStr, -- :: Handle -> String -> SIO ()+ hSeek, -- :: Handle -> SeekMode -> Integer -> SIO ()+ hSetBinaryMode, -- :: Handle -> Bool -> SIO ()+ hSetBuffering, -- :: Handle -> BufferMode -> SIO ()+ hSetEcho, -- :: Handle -> Bool -> SIO ()+ hSetFileSize, -- :: Handle -> Integer -> SIO ()+ hSetPosn, -- :: HandlePosn -> SIO ()+ hShow, -- :: Handle -> SIO String+ hTell, -- :: Handle -> SIO Integer+ hWaitForInput, -- :: Handle -> Int -> SIO Bool+ isEOF, -- :: SIO Bool+ openBinaryFile, -- :: FilePath -> IOMode -> SIO Handle+ openFile, -- :: FilePath -> IOMode -> SIO Handle+ stderr, -- :: Handle+ stdin, -- :: Handle+ stdout -- :: Handle+)+where++import Prelude (Bool, Int, Integer, String, Char, FilePath, Read, Show, (.), seq)+import Control.Parallel.Strategies (NFData(..))+import System.IO (IOMode, Handle, BufferMode, HandlePosn, SeekMode)+import GHC.Ptr (Ptr)+import System.IO.Strict.Internals+import qualified System.IO.Strict.Internals as SIO+import qualified System.IO as IO++-- | Note that 'getContents' is stricter than its counterpart in "System.IO".+getContents :: SIO String+getContents = wrap0' IO.getContents++-- | Note that 'hGetContents' is stricter than its counterpart in "System.IO".+hGetContents :: Handle -> SIO String+hGetContents = wrap1' IO.hGetContents++-- | Note that 'withBinaryFile' is stricter than its counterpart in "System.IO".+withBinaryFile :: NFData sr => FilePath -> IOMode -> (Handle -> SIO sr) -> SIO sr+withBinaryFile fp mode kont = wrap0' (IO.withBinaryFile fp mode (SIO.run . kont))++-- | Note that 'withFile' is stricter than its counterpart in "System.IO".+withFile :: NFData sr => FilePath -> IOMode -> (Handle -> SIO sr) -> SIO sr+withFile fp mode kont = wrap0' (IO.withFile fp mode (SIO.run . kont))++-- | Note that 'fix' is stricter than its counterpart in "System.IO".+fix :: NFData sa => (sa -> SIO sa) -> SIO sa+fix kont = wrap0' (IO.fixIO (SIO.run . kont))++-- | Note that 'readFile' is stricter than its counterpart in "System.IO".+readFile :: FilePath -> SIO String+readFile = wrap1' IO.readFile++-- | Note that 'read' is stricter than its counterpart in "System.IO".+read :: (NFData sa, Read sa) => String -> SIO sa+read = wrap1' IO.readIO++-- | Note that 'readLn' is stricter than its counterpart in "System.IO".+readLn :: (NFData sa, Read sa) => SIO sa+readLn = wrap0' IO.readLn++getChar :: SIO Char+getChar = wrap0 IO.getChar++appendFile :: FilePath -> String -> SIO ()+appendFile = wrap2 IO.appendFile++getLine :: SIO String+getLine = wrap0 IO.getLine+hPrint :: (Show a) => Handle -> a -> SIO ()+hPrint = wrap2 IO.hPrint+hPutStrLn :: Handle -> String -> SIO ()+hPutStrLn = wrap2 IO.hPutStrLn+hReady :: Handle -> SIO Bool+hReady = wrap1 IO.hReady+interact :: (String -> String) -> SIO ()+interact = wrap1 IO.interact+openBinaryTempFile :: FilePath -> String -> SIO (FilePath, Handle)+openBinaryTempFile = wrap2 IO.openBinaryTempFile+openTempFile :: FilePath -> String -> SIO (FilePath, Handle)+openTempFile = wrap2 IO.openTempFile+print :: (Show a) => a -> SIO ()+print = wrap1 IO.print+putChar :: Char -> SIO ()+putChar = wrap1 IO.putChar+putStr :: String -> SIO ()+putStr = wrap1 IO.putStr+putStrLn :: String -> SIO ()+putStrLn = wrap1 IO.putStrLn+writeFile :: FilePath -> String -> SIO ()+writeFile = wrap2 IO.writeFile+hClose :: Handle -> SIO ()+hClose = wrap1 IO.hClose+hFileSize :: Handle -> SIO Integer+hFileSize = wrap1 IO.hFileSize+hFlush :: Handle -> SIO ()+hFlush = wrap1 IO.hFlush+hGetBuf :: Handle -> Ptr a -> Int -> SIO Int+hGetBuf = wrap3 IO.hGetBuf+hGetBufNonBlocking :: Handle -> Ptr a -> Int -> SIO Int+hGetBufNonBlocking = wrap3 IO.hGetBufNonBlocking+hGetBuffering :: Handle -> SIO BufferMode+hGetBuffering = wrap1 IO.hGetBuffering+hGetChar :: Handle -> SIO Char+hGetChar = wrap1 IO.hGetChar+hGetEcho :: Handle -> SIO Bool+hGetEcho = wrap1 IO.hGetEcho+hGetLine :: Handle -> SIO String+hGetLine = wrap1 IO.hGetLine+hGetPosn :: Handle -> SIO HandlePosn+hGetPosn = wrap1 IO.hGetPosn +hIsClosed :: Handle -> SIO Bool+hIsClosed = wrap1 IO.hIsClosed+hIsEOF :: Handle -> SIO Bool+hIsEOF = wrap1 IO.hIsEOF+hIsOpen :: Handle -> SIO Bool+hIsOpen = wrap1 IO.hIsOpen+hIsReadable :: Handle -> SIO Bool+hIsReadable = wrap1 IO.hIsReadable+hIsSeekable :: Handle -> SIO Bool+hIsSeekable = wrap1 IO.hIsSeekable +hIsTerminalDevice :: Handle -> SIO Bool+hIsTerminalDevice = wrap1 IO.hIsTerminalDevice+hIsWritable :: Handle -> SIO Bool+hIsWritable = wrap1 IO.hIsWritable +hLookAhead :: Handle -> SIO Char+hLookAhead = wrap1 IO.hLookAhead+hPutBuf :: Handle -> Ptr a -> Int -> SIO ()+hPutBuf = wrap3 IO.hPutBuf+hPutBufNonBlocking :: Handle -> Ptr a -> Int -> SIO Int+hPutBufNonBlocking = wrap3 IO.hPutBufNonBlocking+hPutChar :: Handle -> Char -> SIO ()+hPutChar = wrap2 IO.hPutChar+hPutStr :: Handle -> String -> SIO ()+hPutStr = wrap2 IO.hPutStr+hSeek :: Handle -> SeekMode -> Integer -> SIO ()+hSeek = wrap3 IO.hSeek+hSetBinaryMode :: Handle -> Bool -> SIO ()+hSetBinaryMode = wrap2 IO.hSetBinaryMode+hSetBuffering :: Handle -> BufferMode -> SIO ()+hSetBuffering = wrap2 IO.hSetBuffering+hSetEcho :: Handle -> Bool -> SIO ()+hSetEcho = wrap2 IO.hSetEcho+hSetFileSize :: Handle -> Integer -> SIO ()+hSetFileSize = wrap2 IO.hSetFileSize+hSetPosn :: HandlePosn -> SIO ()+hSetPosn = wrap1 IO.hSetPosn +hShow :: Handle -> SIO String+hShow = wrap1 IO.hShow+hTell :: Handle -> SIO Integer+hTell = wrap1 IO.hTell+hWaitForInput :: Handle -> Int -> SIO Bool+hWaitForInput = wrap2 IO.hWaitForInput+isEOF :: SIO Bool+isEOF = wrap0 IO.isEOF+openBinaryFile :: FilePath -> IOMode -> SIO Handle+openBinaryFile = wrap2 IO.openBinaryFile+openFile :: FilePath -> IOMode -> SIO Handle+openFile = wrap2 IO.openFile+stderr :: Handle+stderr = IO.stderr+stdin :: Handle+stdin = IO.stdin+stdout :: Handle+stdout = IO.stdout
+ System/IO/Strict/Internals.hs view
@@ -0,0 +1,100 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+--------------------------------------------------------------------+-- |+-- Module : System.IO.Strict.Internals+-- Copyright : (c) Nicolas Pouillard 2009+-- License : BSD3+--+-- Maintainer : Nicolas Pouillard <nicolas.pouillard@gmail.com>+-- Stability : provisional+--+-- This module exports the internals of "System.IO.Strict" so that other packages can extend the+-- 'SIO' monad. This module has to be used with great care: by lifting a lazy+-- function or a function that let leaks its lazy arguments, one breaks the only purpose+-- of the "System.IO.Strict" module.+--------------------------------------------------------------------++module System.IO.Strict.Internals+(+ -- * Types+ SIO(..),++ -- * Running the 'SIO' monad+ run,++ -- * A stricter 'return'+ return',+ + -- * Wrapping functions+ wrap0, -- :: IO a -> SIO a+ wrap0', -- :: NFData sa => IO sa -> SIO sa+ wrap1, -- :: (a -> IO b) -> a -> SIO b+ wrap1', -- :: NFData sb => (a -> IO sb) -> a -> SIO sb+ wrap2, -- :: (a -> b -> IO c) -> a -> b -> SIO c+ wrap2', -- :: NFData sc => (a -> b -> IO sc) -> a -> b -> SIO sc+ wrap3, -- :: (a -> b -> c -> IO d) -> a -> b -> c -> SIO d+ wrap3', -- :: NFData sd => (a -> b -> c -> IO sd) -> a -> b -> c -> SIO sd+)+where++import Prelude ((.), seq)+import Control.Parallel.Strategies (NFData(..))+import Control.Monad+import Control.Monad.Fix+-- import Control.Monad.Error+import Control.Applicative+import System.IO (IO)+import qualified System.IO as IO++newtype SIO a = SIO { rawRun :: IO a }+ deriving (Functor, Applicative, Monad, MonadFix {-, MonadPlus, MonadError IOError-}) -- Not MonadIO !!!!++-- | 'run' allows to return to the wider world of 'IO's.+run :: NFData sa => SIO sa -> IO sa+run mx = rawRun mx >>= return'+{-# INLINE run #-}++-- | A stricter version of 'return', that works for every monad.+return' :: (Monad m, NFData sa) => sa -> m sa+return' x = rnf x `seq` return x+{-# INLINE return' #-}++-- | Wraps a strict /IO/ computation without arguments.+wrap0 :: IO a -> SIO a+wrap0 = SIO+{-# INLINE wrap0 #-}++-- | Wraps a lazy /IO/ computation without arguments and forces its contents.+wrap0' :: NFData sa => IO sa -> SIO sa+wrap0' mx = SIO (do x <- mx; rnf x `seq` return x)+{-# INLINE wrap0' #-}++-- | Wraps a strict /IO/ computation with a single argument.+wrap1 :: (a -> IO b) -> a -> SIO b+wrap1 = (wrap0 .)+{-# INLINE wrap1 #-}++-- | Wraps a lazy /IO/ computation with a single argument and forces its contents.+wrap1' :: NFData sb => (a -> IO sb) -> a -> SIO sb+wrap1' = (wrap0' .)+{-# INLINE wrap1' #-}++-- | Wraps a strict /IO/ computation with two arguments.+wrap2 :: (a -> b -> IO c) -> a -> b -> SIO c+wrap2 = (wrap1 .)+{-# INLINE wrap2 #-}++-- | Wraps a strict /IO/ computation with two arguments and forces its contents.+wrap2' :: NFData sc => (a -> b -> IO sc) -> a -> b -> SIO sc+wrap2' = (wrap1' .)+{-# INLINE wrap2' #-}++-- | Wraps a strict /IO/ computation with two arguments.+wrap3 :: (a -> b -> c -> IO d) -> a -> b -> c -> SIO d+wrap3 = (wrap2 .)+{-# INLINE wrap3 #-}++-- | Wraps a strict /IO/ computation with two arguments and forces its contents.+wrap3' :: NFData sd => (a -> b -> c -> IO sd) -> a -> b -> c -> SIO sd+wrap3' = (wrap2' .)+{-# INLINE wrap3' #-}
+ strict-io.cabal view
@@ -0,0 +1,32 @@+name: strict-io+cabal-Version: >=1.6+version: 0.1+license: BSD3+license-File: LICENSE+copyright: (c) Nicolas Pouillard+author: Nicolas Pouillard+maintainer: Nicolas Pouillard <nicolas.pouillard@gmail.com>+category: System+synopsis: A library wrapping standard IO modules to provide strict IO.+description: This library is a thin layer on top standard IO modules like System.IO+ that re-expose these functions under a different type, namely SIO.+stability: Provisional+build-type: Simple++library+ build-depends: base>=3.0, parallel, extensible-exceptions+ exposed-modules: System.IO.Strict+ System.IO.Strict.Internals+ Data.IORef.Strict+ -- TODO Control.Exception.Strict+ ghc-options: -Wall -O2++source-repository head+ type: darcs+ location: http://patch-tag.com/publicrepos/strict-io++source-repository this+ type: darcs+ location: http://patch-tag.com/publicrepos/strict-io+ tag: 0.1+