phooey-0.3: src/Graphics/UI/Phooey/AFA.hs
{-# OPTIONS -fglasgow-exts -farrows #-}
----------------------------------------------------------------------
-- |
-- Module : Graphics.UI.Phooey.AFA
-- 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 an arrow
-- and an applicative functor. (Hence the name \"AFA\".) 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), nothing can be
-- known about the function @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.AFA where
import Control.Arrow hiding (pure)
import Control.Applicative (Applicative, liftA,liftA2)
newtype AFA (~>) src i o = AFA (src i ~> src o)
instance {-""-} (Arrow (~>), Applicative src)
=> Arrow (AFA (~>) src) where
arr f = AFA (arr (liftA f))
AFA ab >>> AFA bc = AFA (ab >>> bc)
first (AFA a) =
AFA (arr splitA >>> first a >>> arr mergeA)
instance {-""-} (ArrowLoop (~>), Applicative src)
=> ArrowLoop (AFA (~>) src) where
-- loop :: UI (b,d) (c,d) -> UI b c
loop (AFA k) =
AFA (loop (arr mergeA >>> k >>> arr splitA))
mergeA :: Applicative m => (m a, m c) -> m (a,c)
mergeA ~(ma,mc) = liftA2 (,) ma mc
splitA :: Applicative m => m (a,b) -> (m a, m b)
splitA m = (liftA fst m, liftA snd m)