pollatron

Untitled

Jul 21st, 2025
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE DeriveFunctor #-}
  2. {-# LANGUAGE GADTs #-}
  3.  
  4. import Data.Time.Clock (UTCTime, diffUTCTime, getCurrentTime)
  5. import Control.Monad.ST
  6. import Data.IORef
  7.  
  8. -- warning: clunky Free monad implementation
  9. data Free f a = Pure a | Run (f (Free f a))
  10. instance (Functor f) => Monad (Free f) where
  11.   return = Pure
  12.   (>>=) (Pure a) f = f a
  13.   (>>=) (Run r) f = Run $ fmap (>>= f) r
  14. instance (Functor f) => Functor (Free f) where
  15.   fmap = undefined
  16. instance (Functor f) => Applicative (Free f) where
  17.   (<*>) = undefined
  18.   pure = return
  19. liftF :: (Functor f) => f a -> Free f a
  20. liftF x = Run (fmap Pure x)
  21.  
  22.  
  23. data SomePromise where
  24.     SomePromise :: IORef (Promise a) -> SomePromise
  25.  
  26. data PromiseF a
  27.     = PLift (IO a) -- run an effect and yield
  28.     | PQueue SomePromise (() -> a) -- add a new anonymous thread to the event loop
  29.     deriving Functor
  30. type Promise = Free PromiseF
  31.  
  32. liftP :: IO a -> Promise a
  33. liftP = liftF . PLift
  34.  
  35. data Handle a = Handle (Promise (Maybe a))
  36. scan (Handle handle) = handle
  37. fork :: Promise a -> Promise (Handle a)
  38. fork p = do
  39.     forkRef <- liftP $ newIORef p
  40.     liftF $ PQueue (SomePromise forkRef) id
  41.     return (Handle $ do
  42.         p' <- liftP $ readIORef forkRef
  43.        return $ case p' of
  44.             Pure a -> Just a
  45.             Run _ -> Nothing)
  46.  
  47. step :: IORef [SomePromise] -> IORef (Promise a) -> IO (Maybe a)
  48. step threadsRef threadRef = do
  49.     r <- readIORef threadRef
  50.     case r of
  51.         Pure a -> return (Just a) -- thread done!
  52.         Run (PQueue t c) -> do
  53.             modifyIORef threadsRef (t :)
  54.             writeIORef threadRef (c ())
  55.             return Nothing
  56.         Run (PLift mr) -> (mr >>= writeIORef threadRef) >> return Nothing
  57.  
  58. runPromise :: Promise a -> IO a
  59. runPromise root = do
  60.     threadsRef <- newIORef []
  61.     rootRef <- newIORef root
  62.     let forever = do
  63.             r <- step threadsRef rootRef
  64.             case r of
  65.                 Just a -> return a
  66.                 Nothing -> do
  67.                     -- update the other threads and keep going
  68.                     threads <- readIORef threadsRef
  69.                     foldr (\(SomePromise p) acc -> step threadsRef p >> acc >> return ())
  70.                         (return ()) threads
  71.                     forever
  72.     forever
  73.  
  74. ---------------------------------------------------------------------------------------------
  75.  
  76. await :: Handle a -> Promise a
  77. await handle = do
  78.     ma <- scan handle
  79.     case ma of
  80.         Just a -> return a -- done!
  81.         Nothing -> await handle -- take a break and try again later
  82.  
  83. testAsync :: Float -> String -> Promise String
  84. testAsync t n = do
  85.     liftP $ putStrLn (n ++ " called")
  86.     timeout t
  87.     liftP $ putStrLn (n ++ " did some stuff, it's halfway through now")
  88.     timeout t
  89.     return (n ++ " has finished")
  90.  
  91. test :: Promise ()
  92. test = do
  93.     liftP $ putStrLn "Hello World"
  94.     handle1 <- fork $ testAsync 2 "test2"
  95.     handle2 <- fork $ testAsync 3 "test3"
  96.     liftP $ putStrLn "Tests invoked"
  97.     await handle1
  98.     await handle2
  99.     liftP $ putStrLn "All done, yay!"
  100.     return ()
  101.  
  102. timeout :: Float -> Promise () -- empty promise; yields while waiting, resolves once finished
  103. timeout length = do
  104.     start <- liftP $ getCurrentTime
  105.     let waitUntil = do
  106.             curr <- liftP $ getCurrentTime
  107.             if realToFrac (diffUTCTime curr start) > length then return ()
  108.             else waitUntil -- not done yet; allow eventloop to work on other promises
  109.     waitUntil
  110.  
  111. main = runPromise test
  112.  
Advertisement
Add Comment
Please, Sign In to add comment