packages feed

fay-0.24.2.0: examples/Cont.hs

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE NoImplicitPrelude #-}

-- | An example implementation of the lovely continuation monad.

module Cont where

import FFI
import Prelude

--------------------------------------------------------------------------------
-- Entry point.

-- | Main entry point.
main :: Fay ()
main = runContT demo (const (return ()))

demo :: Deferred ()
demo = case contT of
  CC return (>>=) (>>) callCC lift -> do
    lift (putStrLn "Hello!")
    sync setTimeout 500
    contents <- sync readFile "README.md"
    lift (putStrLn ("File contents is: " ++ take 10 contents ++ "..."))

--------------------------------------------------------------------------------
-- Deferred library.

-- | An example deferred monad.
type Deferred a = ContT () Fay a

-- | Set an asynchronous timeout.
setTimeout :: Int -> (() -> Fay ()) -> Fay ()
setTimeout = ffi "global.setTimeout(%2,%1)"

readFile :: String -> (String -> Fay b) -> Fay b
readFile = ffi "require('fs').readFile(%1,'utf-8',function(_,s){ %2(s); })"

sync :: (t -> (a -> Fay r) -> Fay r) -> t -> ContT r Fay a
sync m a = ContT $ \c -> m a c

--------------------------------------------------------------------------------
-- Continuation library.

-- | The continuation monad.
data ContT r m a = ContT { runContT :: (a -> m r) -> m r }
class Monad (m :: * -> *)
instance (Monad m) => Monad (ContT r m)

data CC = CC
  { cc_return :: forall a r. a -> ContT r Fay a
  , cc_bind :: forall a b r. ContT r Fay a -> (a -> ContT r Fay b) -> ContT r Fay b
  , cc_then :: forall a b r. ContT r Fay a -> ContT r Fay b -> ContT r Fay b
  , cc_callCC :: forall a b r. ((a -> ContT r Fay b) -> ContT r Fay a) -> ContT r Fay a
  , cc_lift :: forall a r. Fay a -> ContT r Fay a
  }

-- | The continuation monad module.
contT =
  let return a = ContT (\f -> f a)
      m >>= k = ContT $ \c -> runContT m (\a -> runContT (k a) c)
      m >> n = m >>= \_ -> n
      callCC f = ContT $ \c -> runContT (f (\a -> ContT $ \_ -> c a)) c
      lift m = ContT (\x -> m >>=* x)
  in CC return (>>=) (>>) callCC lift where (>>=*) = (>>=)