phooey-1.0: src/Examples/Monad.hs
{-# OPTIONS -fglasgow-exts #-}
----------------------------------------------------------------------
-- |
-- Module : Examples.Monad
-- Copyright : (c) Conal Elliott 2007
-- License : LGPL
--
-- Maintainer : conal@conal.net
-- Stability : experimental
-- Portability : portable
--
-- Monadic-style Phooey examples. Use 'runUI'
----------------------------------------------------------------------
module Examples.Monad where
import Control.Applicative
import Control.Monad (liftM2)
import Control.Monad.Fix
import Data.Monoid (mappend,mempty)
import Graphics.UI.Phooey.Monad
-- h :: UI (Source String)
-- h = return (pure "Hello World!")
-- uia,uib :: UI (Source ())
-- uia = stringDisplay =<< h
-- uib = showDisplay =<< sl0 3
ui1 :: UI (Source ())
ui1 = title "Shopping List" $
do a <- title "apples" $ islider (0,10) 3
b <- title "bananas" $ islider (0,10) 7
title "total" $ showDisplay (liftA2 (+) a b)
-- Refactoring
sl0 :: IWidget Int
sl0 = islider (0,10)
apples, bananas :: UI (Source Int)
apples = title "apples" $ sl0 3
bananas = title "bananas" $ sl0 7
total :: Num a => OWidget a
total = title "total" . showDisplay
ui1x :: UI (Source ())
ui1x = title "Shopping List" $
do a <- apples
b <- bananas
total (liftA2 (+) a b)
fruit :: UI (Source Int)
fruit = liftM2 (liftA2 (+)) apples bananas
ui1y :: UI (Source ())
ui1y = title "Shopping List" $ fruit >>= total
-- In the two examples above, visual layout is implicitly chosen to be
-- top-down, following the order in which the components are declared in
-- the arrow expressions. This choice may be overridden, as in the
-- following examples.
uiB1 = fromBottom ui1
uiL1 = fromLeft ui1
uiR1 = fromRight ui1
ui3 = fromBottom $
title "Shopping List" $
fromRight fruit >>= total
-- Experiments with multiple displays
uix = do n <- sl0 3
liftM2 mappend
(showDisplay (liftA (*2) n))
(showDisplay (liftA (*3) n))
-- Dynamic
ui2 :: UI (Source ())
ui2 = do l <- title "lo" $ sl0 3
h <- title "hi" $ sl0 8
v <- title "val" $ isliderDyn (pair l h) 5
title "factorial" $ showDisplay (liftA fact v)
fact :: Int -> Int
fact n = product [1 .. n]
-- Refactor
lo,hi :: UI (Source Int)
lo = title "lo" $ sl0 3
hi = title "hi" $ sl0 8
bounds :: UI (Source (Int,Int))
bounds = liftM2 pair lo hi
val :: UI (Source Int)
val = do b <- bounds
title "val" $ isliderDyn b 5
-- Alternative style, in which the "val" title is around the lo & hi
-- sliders as well. This layout reflects the purpose of the lo & hi
-- sliders.
val' = title "val" $
do b <- bounds
isliderDyn b 5
ui2' = do v <- val'
title "factorial" $ showDisplay (liftA fact v)
-- Recursive
uir1 :: UI (Source ())
uir1 = mdo l <- title "lo" $ isliderDyn (pair (pure 0) h) 3
h <- title "hi" $ isliderDyn (pair l (pure 10)) 8
v <- title "val" $ isliderDyn (pair l h) 5
title "factorial" $ showDisplay (liftA fact v)
-- Refactor
boundsR :: UI (Source (Int,Int))
boundsR = mfix boundsF
where
boundsF lh = liftM2 pair
(title "lo" $ isliderDyn (pair (pure 0) h) 3)
(title "hi" $ isliderDyn (pair l (pure 10)) 8)
where
(l,h) = unPair lh
unPair :: Functor f => f (a, b) -> (f a, f b)
unPair p = (fmap fst p, fmap snd p)
valR :: UI (Source Int)
valR = do b <- boundsR
title "val" $ isliderDyn b 5
uir1' = do v <- valR
title "factorial" $ showDisplay (liftA fact v)
uir2 = mdo v <- title "val" (isliderDyn (liftA (plusMinus 5) v) 6)
title "squared" (showDisplay (liftA square v))
where
plusMinus n x = (x-n,x+n)
square y = y*y
pair :: Applicative f => f a -> f b -> f (a,b)
pair = liftA2 (,)