File: IO.hs

package info (click to toggle)
bali-phy 4.0~beta16%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 15,192 kB
  • sloc: cpp: 119,288; xml: 13,482; haskell: 9,722; python: 2,930; yacc: 1,329; perl: 1,169; lex: 904; sh: 343; makefile: 26
file content (55 lines) | stat: -rw-r--r-- 1,962 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{-# LANGUAGE NoImplicitPrelude #-}

module Compiler.IO (module Compiler.IO, module Control.Monad) where

import Compiler.Base
import Data.Tuple     -- for snd

import Data.Function  -- for (.)
import Data.Functor
import Control.Applicative
import Control.Monad

type RealWorld = Int

-- We effectively have (!RealWorld, a).  Currently we are doing this manually.
-- We can't do         (!RealWorld, !a), as this would undermine unsafeInterleaveIO.


data IO a = IO { runIO :: RealWorld -> (RealWorld,a) }

instance Functor IO where
    fmap f x = IO (\state1 -> let (state2,   result) = runIO x state1
                              in  state2 `seq` (state2, f result))

instance Applicative IO where
    pure x  = IO (\s -> (s,x))
    t1 <*> t2 = IO (\state1 -> let (state2,f) = runIO t1 state1
                                   (state3,x) = runIO t2 state2
                               in state3 `seq` (state3, f x))

instance Monad IO where
    f >>= g  = IO (\state1 -> case runIO f state1 of (state2,x) -> runIO (g x) state2)
    unsafeInterleaveIO f = IO (\s -> s `seq` (s, snd (runIO f s)) )

fixIO f   = IO (\state1 -> let result@(state2,x) = runIO (f x) state1 in result)

unsafePerformIO :: IO c -> c
unsafePerformIO f = let (s,x) = runIO f 0#
                    in x

foreign import bpcall "Modifiables:changeable_apply" _changeable_apply :: (a -> b) -> a -> b
changeableIO f = IO (\s -> _changeable_apply (runIO f) s)

-- We used to have let x = s `seq` f s in (x `seq` s, x).
-- * (s `seq` f s) emulates forcing s, so that the C++ code doesn't have to do so.
-- * (x `seq` s)   ensures that getting the new state forces f to run.

-- However, the new form allows merging the seqs, and allows eliminating seqs else where.
-- It also avoids doing (s `seq` x `seq` s) for the state.

makeIO f = IO (\s -> let x = f s in x `seq` s `seq` (s, x))

lazySequence :: Functor f => f (IO a) -> IO (f a)
lazySequence obj = return $ fmap unsafePerformIO obj