phooey-0.1: src/Graphics/UI/Phooey/AmA.hs
{-# OPTIONS #-}
----------------------------------------------------------------------
-- |
-- Module : Graphics.UI.Phooey.AmA
-- Copyright : (c) Conal Elliott 2006
-- License : LGPL
--
-- Maintainer : conal@conal.net
-- Stability : provisional
-- Portability : portable
--
-- This module captures a pattern that for building an arrow from a monad
-- and an arrow. (Hence the name "AmA".) Motivation follows.
--
-- The UI monad makes for simple examples, but an awkwardness remains,
-- namely explicit Source types. The reason for Source types is that
-- in a monadic bind, @m >>= f@ (as hidden in @do@ notation), the
-- function nothing can be known about @f@ until it is applied to a value
-- generated by @m@. In other words, the monadic interface prevents us
-- from accessing the static aspects of @f@ and separating them from the
-- dynamic aspects. This difficulty is the main motivation for
-- generalizing monads to arrows.
----------------------------------------------------------------------
module Graphics.UI.Phooey.AmA where
import Control.Arrow
import Control.Monad (liftM,liftM2)
-- newtype AmA (~>) src i o = AmA (src i ~> src o)
-- Workaround for haddock limitation
-- newtype AmA arr src i o = AmA (src i `arr` src o)
newtype AmA arr src i o = AmA (arr (src i) (src o))
instance {-""-} (Arrow arr, Monad src)
=> Arrow (AmA arr src) where
pure f = AmA (pure (liftM f))
AmA ab >>> AmA bc = AmA (ab >>> bc)
first (AmA a) =
AmA (pure splitM >>> first a >>> pure mergeM)
instance {-""-} (ArrowLoop arr, Monad src)
=> ArrowLoop (AmA arr src) where
-- loop :: UI (b,d) (c,d) -> UI b c
loop (AmA k) =
AmA (loop (pure mergeM >>> k >>> pure splitM))
mergeM :: Monad m => (m a, m c) -> m (a,c)
mergeM ~(ma,mc) = liftM2 (,) ma mc
splitM :: Monad m => m (a,b) -> (m a, m b)
splitM m = (liftM fst m, liftM snd m)