packages feed

phooey-1.2: src/Examples/Applicative.hs

{-# OPTIONS #-}

----------------------------------------------------------------------
-- |
-- Module      :  Examples.Applicative
-- Copyright   :  (c) Conal Elliott 2007
-- License     :  LGPL
-- 
-- Maintainer  :  conal@conal.net
-- Stability   :  experimental
-- Portability :  portable
-- 
-- Applicative-style Phooey examples.  Use 'runUI'
----------------------------------------------------------------------

module Examples.Applicative where

import Control.Applicative
import Control.Monad.Fix (fix)

import Graphics.UI.Phooey.Applicative

-- For oPair etc
import Control.DataDriven (Sink,Updater)
import Data.Monoid

h :: UI String
h = pure "Hello World!"

sl0 :: IWidget Int
sl0 = islider (0,10)

uia,uib :: UI Upd
uia = stringDisplay <*> h
uib = showDisplay <*> sl0 3


ui1 :: UI Upd
ui1 = title "Shopping List" $ fruit <**> total

apples, bananas, fruit :: UI Int
apples  = title "apples"  (sl0 3)
bananas = title "bananas" (sl0 7)

fruit = liftA2 (+) apples bananas

-- With overloading, we could say
-- fruit = apples + bananas

total :: Num a => OWidget a
total = title "total" showDisplay


pair :: Applicative f => f a -> f b -> f (a,b)
pair = liftA2 (,)

lo,hi :: UI Int
lo = title "lo" $ sl0 2
hi = title "hi" $ sl0 8

val :: UI Int
val = title "val" $ isliderDyn (pair lo hi) 5

-- Note that the "val" title is around the lo & hi sliders as well.  I
-- guess that layout reflects the purpose of the lo & hi sliders.  I don't
-- know how to get a "val" title on just the dynamically-bounded slider.
ui2 :: UI Upd
ui2 = (fact <$> val) <**> title "factorial" showDisplay

-- minor variation
ui2' = val <**>
       pure fact <**>
       title "factorial" showDisplay

-- Variation

fact :: Int -> Int
fact n = product [1 .. n]


o1 :: UI (Snk (Int -> Int -> Int))
o1 = oLambda apples (oLambda bananas total)

ui4 :: UI Upd
ui4 = o1 <*> pure (+)

-- Experiments.  None of these functions is specific to UI

-- iPair :: Applicative ui => ui a -> ui b -> ui (a,b)
-- iPair = liftA2 (,) -- fromLeft

-- oPair :: (Applicative ui, Applicative src, Monoid (Updater src))
--       => ui (Sink src a) -> ui (Sink src b) -> ui (Sink src (a,b))
-- oPair = liftA2 oPair'  -- fromLeft

-- -- Suggested use: m = src ()
-- oLambda :: Applicative ui
--         => ui a -> ui (b -> m) -> ui ((a->b) -> m)
-- oLambda = liftA2 oLambda'  -- fromTop

-- -- Monoid variant for oPair

-- oPairM :: (Applicative ui, Monoid m)
--        => ui (a -> m) -> ui (b -> m) -> ui ((a,b) -> m)
-- oPairM = liftA2 oPairM'

-- oPairM' :: Monoid m => (a -> m) -> (b -> m) -> ((a,b) -> m)
-- oPairM' oa ob (a,b) = oa a `mappend` ob b  -- fromLeft

iPair :: UI a -> UI b -> UI (a,b)
iPair a b = fromLeft (liftA2 (,) a b)

oPair :: (Monoid (Updater src), Applicative src)  -- e.g., src == IO
      => UI (Sink src a) -> UI (Sink src b) -> UI (Sink src (a,b))
oPair a b = fromLeft (liftA2 oPair' a b)

oPair' :: (Monoid (Updater src), Applicative src)
       => Sink src a -> Sink src b -> Sink src (a,b)
oPair' oa ob (a,b) = oa a `mappend` ob b

-- Suggested use: m = src ()
oLambda :: UI a -> UI (b -> m) -> UI ((a->b) -> m)
oLambda a b = fromTop (liftA2 oLambda' a b)

oLambda' :: a -> (b -> m) -> ((a->b) -> m)
oLambda' ia ob f = ob (f ia)


o2 :: UI (Snk ((Int,Int) -> Int))
o2 = oLambda (iPair apples bananas) total

ui5 :: UI Upd
ui5 = o2 <*> pure (uncurry (+))

o3 :: UI (Snk ((Int,Int) -> (Int,Int))) 
o3 = oLambda (iPair sli sli) (oPair slo slo)
 where
   sli = sl0 5
   slo = isliderDisplay (0,10)

ui6 :: UI Upd
ui6 = o3 <*> pure (\ (a,b) -> (b,a))


---- Recursive:

-- ffix :: Functor f => f (a->a) -> f a
-- ffix = fmap fix

-- or
-- ffix :: (m a -> m a) -> m a
-- ffix = fix

unPair :: Functor f => f (a, b) -> (f a, f b)
unPair p = (fmap fst p, fmap snd p)

ui7 :: UI (Int,Int)
ui7 = fix f
 where f :: UI (Int,Int) -> UI (Int,Int)
       f bounds = liftA2 (,)
                    (isliderDyn (pair (pure  0) hi) 3)
                    (isliderDyn (pair lo (pure 10)) 8)
        where
          ~(lo,hi) = unPair bounds

ui8 :: UI Upd
ui8 = total <*> fmap (uncurry (+)) ui7

ui9 :: UI Upd
ui9 = fix f *> pure mempty
 where f :: UI Int -> UI Int
       f val = isliderDyn (pair ((subtract 5) <$> val) ((+ 5) <$> val)) 10