lazyio 0.0.3.3 → 0.1
raw patch · 5 files changed
+46/−31 lines, 5 files
Files
- CHANGES +7/−0
- lazyio.cabal +5/−2
- src/System/IO/Lazy.hs +27/−21
- src/System/IO/Lazy/Applicative.hs +3/−3
- src/Test/Main.hs +4/−5
+ CHANGES view
@@ -0,0 +1,7 @@+0.1++* System.IO.Lazy.T: remove MonadIO instance,+liftIO did not satisfy MonadIO laws.+You must use the new function LazyIO.interleave instead.+A positive side-effect is that you do not need+to depend explicitly on 'transformers' anymore.
lazyio.cabal view
@@ -1,5 +1,5 @@ Name: lazyio-Version: 0.0.3.3+Version: 0.1 License: BSD3 License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>@@ -17,6 +17,9 @@ Tested-With: GHC==7.4.1, GHC==7.6.3 Cabal-Version: >=1.6 Build-Type: Simple+Extra-Source-Files:+ CHANGES+ Source-Repository head type: darcs location: http://code.haskell.org/~thielema/lazyio/@@ -24,7 +27,7 @@ Source-Repository this type: darcs location: http://code.haskell.org/~thielema/lazyio/- tag: 0.0.3.3+ tag: 0.1 Flag splitBase description: Choose the new smaller, split-up base package.
src/System/IO/Lazy.hs view
@@ -1,9 +1,9 @@ {- | Caution: -- Although this module calls 'Unsafe.interleaveIO' for you,+- Although this module calls 'unsafeInterleaveIO' for you, it cannot take the responsibility from you.- Using this module is still as unsafe as calling 'Unsafe.interleaveIO' manually.+ Using this module is still as unsafe as calling 'unsafeInterleaveIO' manually. Thus we recommend to wrap the lazy I/O monad into a custom @newtype@ with a restricted set of operations which is considered safe for interleaving I/O actions.@@ -14,25 +14,31 @@ It will also often be the case, that not the complete output is read, and thus the closing action is never reached. It is certainly best to call a closing action after you wrote- the complete result of the lazy I/O monad somewhere+ the complete result of the lazy I/O monad somewhere. -- @return a :: LazyIO a@ is very different from @liftIO (return a) :: LazyIO a@.+- @return a :: LazyIO a@ is very different+ from @interleave (return a) :: LazyIO a@. The first one does not trigger previous IO actions, whereas the second one does.+ This is the reason why we do not instantiate @MonadIO@+ with @liftIO = LazyIO.interleave@,+ despite the matching type signatures.+ One of the @MonadIO@ laws explicitly requires @return a = liftIO (return a)@. - We advise to lift strict IO functions into the lazy IO monad. Lifting a function like @readFile@ may lead to unintended interleaving.+ In the future we may enforce that using the @deepseq@ package. Use it like > import qualified System.IO.Lazy as LazyIO >-> LazyIO.run $-> do liftIO $ putStr "enter first line:"-> x <- liftIO getLine-> liftIO $ putStr "enter second line:"-> y <- liftIO getLine-> return x+> LazyIO.run $ do+> LazyIO.interleave $ putStr "enter first line:"+> x <- LazyIO.interleave getLine+> LazyIO.interleave $ putStr "enter second line:"+> y <- LazyIO.interleave getLine+> return x Because only the first entered line is needed, only the first prompt and the first 'getLine' is executed.@@ -40,9 +46,9 @@ module System.IO.Lazy ( T, run,+ interleave, ) where -import Control.Monad.IO.Class (MonadIO(liftIO), ) import Control.Monad.Trans.State (StateT(StateT), mapStateT, evalStateT, {- runStateT, -} ) import Control.Monad (ap, {- liftM2, -} ) import Control.Applicative (Applicative(pure, (<*>)), )@@ -67,8 +73,8 @@ pure = return (<*>) = ap -instance MonadIO T where- liftIO m = Cons $ StateT $ \RunAll -> fmap (\x->(x,RunAll)) m+interleave :: IO a -> T a+interleave m = Cons $ StateT $ \RunAll -> fmap (\x->(x,RunAll)) m run :: T a -> IO a run =@@ -76,17 +82,17 @@ {- correct:-run $ do x <- liftIO getLine; y <- liftIO getLine; a <- return (x,y); return (fst a)+run $ do x <- interleave getLine; y <- interleave getLine; a <- return (x,y); return (fst a) -*LazyIO> run (Control.Monad.replicateM 5 (liftIO getChar)) >>= putStrLn+*LazyIO> run (Control.Monad.replicateM 5 (interleave getChar)) >>= putStrLn 0011223344 -*LazyIO> run (liftIO (putStrLn "bla") >> liftIO getLine) >>= print+*LazyIO> run (interleave (putStrLn "bla") >> interleave getLine) >>= print "bla 1 1" -*LazyIO> run $ Monad.liftM (\ ((a,b),(c,d))->b) $ liftM2 (,) (liftM2 (,) (liftIO getLine) (liftIO getLine)) (liftM2 (,) (liftIO getLine) (liftIO getLine))+*LazyIO> run $ Monad.liftM (\ ((a,b),(c,d))->b) $ liftM2 (,) (liftM2 (,) (interleave getLine) (interleave getLine)) (liftM2 (,) (interleave getLine) (interleave getLine)) "1 2 2"@@ -94,12 +100,12 @@ {- testLazy, testStrict :: IO String-testLazy = run $ liftM2 (const) (liftIO getLine) (liftIO getLine)-testStrict = run $ liftM2 (flip const) (liftIO getLine) (liftIO getLine)+testLazy = run $ liftM2 (const) (interleave getLine) (interleave getLine)+testStrict = run $ liftM2 (flip const) (interleave getLine) (interleave getLine) test :: IO (String, RunAll) test = flip runStateT RunAll $ decons $- liftIO getLine >>= \x ->- liftIO getLine >>+ interleave getLine >>= \x ->+ interleave getLine >> return x -}
src/System/IO/Lazy/Applicative.hs view
@@ -19,12 +19,12 @@ Cons f <*> Cons x = Cons $ liftM2 (<*>) f x -- instance MonadIO T where-liftIO :: IO a -> T a-liftIO = Cons . Unsafe.interleaveIO . fmap (Chain.Cons Chain.RunAll)+interleave :: IO a -> T a+interleave = Cons . Unsafe.interleaveIO . fmap (Chain.Cons Chain.RunAll) run :: T a -> IO a run = fmap Chain.result . decons {--run $ liftA (\ ~( ~(a,b), ~(c,d)) -> a) $ liftA2 (,) (liftA2 (,) (liftIO getLine) (liftIO getLine)) (liftA2 (,) (liftIO getLine) (liftIO getLine))+run $ liftA (\ ~( ~(a,b), ~(c,d)) -> a) $ liftA2 (,) (liftA2 (,) (interleave getLine) (interleave getLine)) (liftA2 (,) (interleave getLine) (interleave getLine)) -}
src/Test/Main.hs view
@@ -2,11 +2,10 @@ import qualified System.IO.Lazy as LazyIO import qualified System.IO as IO-import Control.Monad.IO.Class (MonadIO(liftIO), )-import Control.Monad.Trans.Reader (ReaderT, runReaderT, asks, )+import System.Exit (exitFailure, ) +import Control.Monad.Trans.Reader (ReaderT(ReaderT), runReaderT, ) import Control.Monad (liftM2, )-import System.Exit (exitFailure, ) import Prelude hiding (getLine, ) @@ -47,7 +46,7 @@ getLine :: HasReadHandle h => ReaderT h LazyIO.T String getLine =- asks getReadHandle >>= \h -> liftIO $ IO.hGetLine h+ ReaderT $ LazyIO.interleave . IO.hGetLine . getReadHandle getLinePair :: HasReadHandle h => ReaderT h LazyIO.T (String, String) getLinePair =@@ -76,7 +75,7 @@ putLine :: HasWriteHandle h => String -> ReaderT h LazyIO.T () putLine str =- asks getWriteHandle >>= \h -> liftIO $ IO.hPutStrLn h str+ ReaderT $ \h -> LazyIO.interleave $ IO.hPutStrLn (getWriteHandle h) str runReadWriteTest :: String -> String -> ReaderT ReadWriteHandle LazyIO.T a -> (a -> IO ()) -> IO ()