module Data.OI.Internal
(
OI
,(:->)
,(??)
,(##)
,(=:)
,dePair
,deList
,deTriple
,deTuple4
,deTuple5
,deTuple6
,deTuple7
,deLeft
,deRight
,runInteraction
,IOResult(..)
,iooi
,iooi'
)
where
import Control.Comonad
import Control.Exception
import Control.Concurrent
import Control.Parallel
import System.IO.Unsafe
data OI a = OI (LeftValueOf a) (RightValueOf a)
type a :-> b = OI a -> b
infixr 0 :->
instance Functor OI where
fmap f = (##) . f . (??)
instance Applicative OI where
pure = (##)
f <*> g = ((f ??) (g ??) ##)
instance Monad OI where
return = (##)
(>>=) = flip ($) . (??)
instance Comonad OI where
extract = (??)
duplicate = (##)
(??) :: OI a -> a
(??) (OI _ val) = val
(##) :: a -> OI a
(##) x = OI (unsafeNew x) x
(=:) :: a -> OI a -> a
(=:) !x (OI var val) = put (return x) var `pseq` val
dePair :: OI (a,b) -> (OI a, OI b)
dePair (OI vxy ~(x,y)) = put io vxy `pseq` (OI vx x, OI vy y)
where
vx = new x
vy = new y
io = (,) <$> lazy (deref vx) <*> lazy (deref vy)
deList :: OI [a] -> Maybe (OI a, OI [a])
deList (OI vxxs xxs) = put io vxxs
`pseq` case xxs of
x:xs -> Just (OI vx x, OI vxs xs)
_ -> Nothing
where
vx = new (undefined :: a)
vxs = new (undefined :: [a])
io = (:) <$> lazy (deref vx) <*> lazy (deref vxs)
deTriple :: OI (a,b,c) -> (OI a, OI b, OI c)
deTriple (OI vxyz ~(x,y,z)) = put io vxyz
`pseq` (OI vx x, OI vy y, OI vz z)
where
vx = new x
vy = new y
vz = new z
io = (,,) <$> lazy (deref vx)
<*> lazy (deref vy)
<*> lazy (deref vz)
deTuple4 :: OI (a,b,c,d) -> (OI a, OI b, OI c, OI d)
deTuple4 (OI vwxyz ~(w,x,y,z)) = put io vwxyz
`pseq` (OI vw w, OI vx x, OI vy y, OI vz z)
where
vw = new w
vx = new x
vy = new y
vz = new z
io = (,,,)
<$> lazy (deref vw)
<*> lazy (deref vx)
<*> lazy (deref vy)
<*> lazy (deref vz)
deTuple5 :: OI (a,b,c,d,e) -> (OI a, OI b, OI c, OI d, OI e)
deTuple5 (OI vvwxyz ~(v,w,x,y,z)) = put io vvwxyz
`pseq` (OI vv v, OI vw w, OI vx x, OI vy y, OI vz z)
where
vv = new v
vw = new w
vx = new x
vy = new y
vz = new z
io = (,,,,)
<$> lazy (deref vv)
<*> lazy (deref vw)
<*> lazy (deref vx)
<*> lazy (deref vy)
<*> lazy (deref vz)
deTuple6 :: OI (a,b,c,d,e,f) -> (OI a, OI b, OI c, OI d, OI e, OI f)
deTuple6 (OI vuvwxyz ~(u,v,w,x,y,z)) = put io vuvwxyz
`pseq` (OI vu u, OI vv v, OI vw w, OI vx x, OI vy y, OI vz z)
where
vu = new u
vv = new v
vw = new w
vx = new x
vy = new y
vz = new z
io = (,,,,,)
<$> lazy (deref vu)
<*> lazy (deref vv)
<*> lazy (deref vw)
<*> lazy (deref vx)
<*> lazy (deref vy)
<*> lazy (deref vz)
deTuple7 :: OI (a,b,c,d,e,f,g) -> (OI a, OI b, OI c, OI d, OI e, OI f, OI g)
deTuple7 (OI vtuvwxyz ~(t,u,v,w,x,y,z)) = put io vtuvwxyz
`pseq` (OI vt t, OI vu u, OI vv v, OI vw w, OI vx x, OI vy y, OI vz z)
where
vt = new t
vu = new u
vv = new v
vw = new w
vx = new x
vy = new y
vz = new z
io = (,,,,,,)
<$> lazy (deref vt)
<*> lazy (deref vu)
<*> lazy (deref vv)
<*> lazy (deref vw)
<*> lazy (deref vx)
<*> lazy (deref vy)
<*> lazy (deref vz)
deLeft :: OI (Either a b) -> Either (OI a) (OI b)
deLeft (OI ve ~(Left a)) = put io ve `pseq` Left (OI vl a)
where
vl = new a
io = Left <$> lazy (deref vl)
deRight :: OI (Either a b) -> Either (OI a) (OI b)
deRight (OI ve ~(Right b)) = put io ve `pseq` Right (OI vr b)
where
vr = new b
io = Right <$> lazy (deref vr)
runInteraction :: (OI a -> b) -> IO b
runInteraction pmain = do
{ v <- newEmptyMVar
; x <- lazy (deref v)
; return $! pmain (OI v x)
}
data IOResult a = Success { result :: a }
| Failure { errmsg :: String }
instance (Show a) => Show (IOResult a) where
show (Success x) = show x
show (Failure e) = e
instance Functor IOResult where
fmap f (Success x) = Success (f x)
fmap _ (Failure e) = Failure e
iooi :: IO a -> OI a -> a
iooi io (OI var val) = put io var `pseq` val
iooi' :: IO a -> OI (IOResult a) -> IOResult a
iooi' io (OI var val)
= put ( do { r <- try io
; case r of { Left e -> return $ Failure (show (e :: SomeException))
; Right a -> return $ Success a }}
) var `par` val
type LeftValueOf a = MVar (IO a)
type RightValueOf a = a
new :: a -> LeftValueOf a
new = unsafeNew
deref :: MVar a -> a
deref = unsafeDeref
put :: a -> MVar a -> a
put = unsafePut
lazy :: IO a -> IO a
lazy = unsafeInterleaveIO
unsafeNew :: a -> LeftValueOf a
unsafeNew _ = unsafePerformIO newEmptyMVar
unsafeDeref :: MVar a -> a
unsafeDeref = unsafePerformIO . readMVar
unsafePut :: a -> MVar a -> a
unsafePut x v = unsafePerformIO $ do
{ s <- tryPutMVar v x
; if s then return x else readMVar v
}