packages feed

arrowp-qq-0.3.0: examples/cgi/CGI.hs

{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}

{-# OPTIONS -F -pgmF arrowp-ext #-}
-- CGI library from Hughes's paper (s.10)

-- This is just an exploratory formulation: it type-checks, but
-- it doesn't actually do anything.

module CGI where

-- Note that this requires a special generalized version of the arrow
-- library, with a special class for first and associates.


import           ArrowContext

data ScriptState
	= Ask
	| Comp (Either ScriptState ScriptState)
	| First ScriptState String

data Input a = Initial a | Resume ScriptState String
data Output a = Final a | Suspend ScriptState String

newtype CGIFunctor a b c = CGI (a (Input b) (Output c))

example :: (ArrowChoice a, ArrowContext a String) => CGIFunctor a b String
example = proc z -> do
		q <- ask -< "What is your question?"
		ans <- ask -< q
		returnA -< "The answer to \"" ++ q ++ "\" is " ++ ans

liftCGI :: ArrowChoice a => a b c -> CGIFunctor a b c
liftCGI f = CGI $ proc (Initial b) -> do
		c <- f -< b
		returnA -< Final c

ask :: ArrowChoice a => CGIFunctor a String String
ask = CGI $ proc x -> case x of
	Initial q -> returnA -< Suspend Ask q
	Resume Ask a -> returnA -< Final a

instance ArrowChoice a => Arrow (CGIFunctor a) where
	arr f = CGI $ proc (Initial b) ->
		returnA -< Final (f b)

	CGI f >>> CGI g = CGI $ proc z -> case z of
			Initial b -> enterf -< Initial                 b
			Resume (Comp (Left s)) a -> enterf -< Resume s a
			Resume (Comp (Right s)) a -> enterg -< Resume s a
		where	enterf = proc x -> do
				y <- f -< x
				case y of
					Final c -> enterg -< Initial c
					Suspend s q -> returnA -<
						Suspend (Comp (Left s)) q
			enterg = proc x -> do
				y <- g -< x
				returnA -< case y of
					Final d -> Final d
					Suspend s q ->
						Suspend (Comp (Right s)) q

instance (ArrowChoice a, ArrowContext a d, Read d, Show d) =>
		ArrowContext (CGIFunctor a) d where
	first (CGI f) = CGI $ proc x -> do
			let (b', d) = case x of
				Initial (b, d) -> (Initial b, d)
				Resume (First s v) a -> (Resume s a, read v)
			c' <- f -< b'
			returnA -< case c' of
				Final c -> Final (c, d)
				Suspend s q -> Suspend (First s (show d)) q


instance ArrowChoice a => ArrowChoice (CGIFunctor a) where
	left (CGI f) = CGI $ proc x -> case x of
			Initial (Left b) -> enterf -< Initial  b
			Initial (Right d) -> returnA -< Final (Right d)
			Resume s a -> enterf -< Resume s       a
		where	enterf = proc x -> do
				y <- f -< x
				case y of
					Final c -> returnA -< Final (Left c)
					Suspend s q -> returnA -< Suspend s q