Phooey
From HaskellWiki
BrettGiles (Talk  contribs) m (→Abstract: Link) 
(overhauling) 

Line 1:  Line 1:  
== Abstract == 
== Abstract == 

−  '''Phooey''' is a functional UI library for [[Haskell]]. Beside this page, here are some ways to explore Phooey: 
+  ''Warning'': The Haddock docs are not ready yet. I'm trying to get a working haddock 2.0 running (on my windows machine). 
+  '''Phooey''' is a functional UI library for [[Haskell]]. Or it's two of them, as it provides a <hask>Monad</hask> interface ''and'' an <hask>Applicative</hask> interface. The simplicity of Phooey's implementation is due to its use of [[DataDriven]] for applicative, datadriven computation. 

+  
+  Besides this wiki page, here are more ways to find out about Phooey: 

* Read [http://darcs.haskell.org/packages/phooey/doc/html the Haddock docs] (with source code, additional examples, and Comment/Talk links). 
* Read [http://darcs.haskell.org/packages/phooey/doc/html the Haddock docs] (with source code, additional examples, and Comment/Talk links). 

* Get the code repository: '''<tt>darcs get http://darcs.haskell.org/packages/phooey</tt>''', or 
* Get the code repository: '''<tt>darcs get http://darcs.haskell.org/packages/phooey</tt>''', or 

Line 9:  Line 12:  
Phooey is also used in [[GuiTV]], a library for composable interfaces and "tangible values". 
Phooey is also used in [[GuiTV]], a library for composable interfaces and "tangible values". 

−  
−  For a draft paper about the implementation of (a future version of) Phooey, please see the paper [[Applicative datadriven programming]]. 

−  
−  The implementation of datadriven computation in Phooey is provided by the [[TypeCompose]] library. 

== Introduction == 
== Introduction == 

Line 24:  Line 23:  
A important reason for using push rather than pull in a GUI implementation is that push is typically much more efficient. A simple pull implementation would either waste time recomputing an unchanging model and view (pegging your CPU for no benefit), or deal with the complexity of avoiding that recomputation. The push style computes only when inputs change. (Continuous change, i.e. animation, negates this advantage of push.) 
A important reason for using push rather than pull in a GUI implementation is that push is typically much more efficient. A simple pull implementation would either waste time recomputing an unchanging model and view (pegging your CPU for no benefit), or deal with the complexity of avoiding that recomputation. The push style computes only when inputs change. (Continuous change, i.e. animation, negates this advantage of push.) 

−  Phooey ("'''Ph'''unctional '''oo'''s'''e'''r '''y'''nterfaces") adopts the declarative style, in which outputs are expressed in terms of inputs. Under the hood, however, the implementation is pushbased (datadriven). Phooey performs the dependency inversion invisibly, so that programmers may express GUIs simply and declaratively while still getting an efficient implementation. I have taken care to structure Phooey's implementation as simply as possible to make clear how this dependency inversion works (subject of paper in progress). In addition, Phooey supports dynamic input bounds, flexible layout, and mutuallyreferential widgets. 
+  Phooey ("'''Ph'''unctional '''oo'''s'''e'''r '''y'''nterfaces") adopts the declarative style, in which outputs are expressed in terms of inputs. Under the hood, however, the implementation is pushbased (datadriven). Phooey uses the [[DataDriven]] library to perform the dependency inversion invisibly, so that programmers may express GUIs simply and declaratively while still getting an efficient implementation. 
Phooey came out of [http://conal.net/Pajama Pajama] and [http://conal.net/papers/Eros Eros]. Pajama is a reimplementation of the [http://conal.net/Pan Pan] language and compiler for function synthesis of interactive, continuous, infinite images. Pan and Pajama use a monadic style for specifying GUIs and are able to do so because they use the implementation trick of [http://conal.net/papers/jfpsaig Compiling Embedded Languages], in which one manipulates expressions rather than values. (This trick is mostly transparent, but the illusion shows through in places.) 
Phooey came out of [http://conal.net/Pajama Pajama] and [http://conal.net/papers/Eros Eros]. Pajama is a reimplementation of the [http://conal.net/Pan Pan] language and compiler for function synthesis of interactive, continuous, infinite images. Pan and Pajama use a monadic style for specifying GUIs and are able to do so because they use the implementation trick of [http://conal.net/papers/jfpsaig Compiling Embedded Languages], in which one manipulates expressions rather than values. (This trick is mostly transparent, but the illusion shows through in places.) 

−  == One example, three interfaces == 
+  == One example, two interfaces == 
As an example, below is a simple shopping list GUI. The <hask>total</hask> displayed at the bottom of the window always shows the sum of the values of the <hask>apples</hask> and <hask>bananas</hask> input sliders. When a user changes the inputs, the output updates accordingly. 
As an example, below is a simple shopping list GUI. The <hask>total</hask> displayed at the bottom of the window always shows the sum of the values of the <hask>apples</hask> and <hask>bananas</hask> input sliders. When a user changes the inputs, the output updates accordingly. 

: [[Image:ui1.png]] 
: [[Image:ui1.png]] 

−  Phooey presents three styles of functional GUI interfaces, structured as a [[monad]], an [[arrow]], and an [[applicative functor]]. Below we present code for the shopping list example in each of the three functional styles. 
+  Phooey presents two styles of functional GUI interfaces, structured as a [[monad]] and as an [[applicative functor]]. (I have removed the original [[arrow]] interface.) Below you can see the code for the shopping list example in each of these styles. 
−  The examples below are all found under [http://darcs.haskell.org/packages/phooey/src/Examples <code>src/Examples/</code>] in the phooey distribution, in the modules [http://darcs.haskell.org/packages/phooey/src/Examples/Monad.hs <code>Monad.hs</code>], [http://darcs.haskell.org/packages/phooey/src/Examples/Arrow.hs <code>Arrow.hs</code>], and [http://darcs.haskell.org/packages/phooey/src/Examples/Applicative.hs <code>Applicative.hs</code>]. In each case, the example is run by loading the corresponding example module into ghci and typing "<hask>runUI ui1</hask>". 
+  The examples below are all found under [http://darcs.haskell.org/packages/phooey/src/Examples <code>src/Examples/</code>] in the phooey distribution, in the modules [http://darcs.haskell.org/packages/phooey/src/Examples/Monad.hs <code>Monad.hs</code>], and [http://darcs.haskell.org/packages/phooey/src/Examples/Applicative.hs <code>Applicative.hs</code>]. In each case, the example is run by loading the corresponding example module into ghci and typing <hask>runUI ui1</hask>. 
=== Monad === 
=== Monad === 

Line 42:  Line 41:  
<haskell> 
<haskell> 

−  ui1 :: UI (Source ()) 
+  ui1 :: UI () 
ui1 = title "Shopping List" $ 
ui1 = title "Shopping List" $ 

do a < title "apples" $ islider (0,10) 3 
do a < title "apples" $ islider (0,10) 3 

Line 54:  Line 53:  
type IWidget a = a > UI (Source a) 
type IWidget a = a > UI (Source a) 

 Output widget type 
 Output widget type 

−  type OWidget a = Source a > UI (Source ()) 
+  type OWidget a = Source a > UI () 
islider :: (Int,Int) > IWidget Int 
islider :: (Int,Int) > IWidget Int 

Line 61:  Line 60:  
</haskell> 
</haskell> 

−  The <hask>Source</hask> type is a [[TypeCompose#Datadriven_computationdatadriven computation]]. By using <hask>Source Int</hask> instead of <hask>Int</hask> for the type of <hask>a</hask> and <hask>b</hask> above, we do not have to rebuild the GUI every time an input value changes. 
+  The [[DataDriven#Source<hask>Source</hask>]] type is a (datadriven) source of timevarying values. By using <hask>Source Int</hask> instead of <hask>Int</hask> for the type of <hask>a</hask> and <hask>b</hask> above, we do not have to rebuild the GUI every time an input value changes. 
The down side of using source types is seen in the <hask>showDisplay</hask> line above, which requires lifting. We could partially hide the lifting behind overloadings of <hask>Num</hask> and other classes (as in [http://conal.net/Fran Fran], [http://conal.net/Pan Pan], and other systems). Some methods, however, do not not have sufficiently flexible types (e.g., <hask>(==)</hask>), and the illusion becomes awkward. The <hask>Arrow</hask> and <hask>Applicative</hask> interfaces hide the source types. 
The down side of using source types is seen in the <hask>showDisplay</hask> line above, which requires lifting. We could partially hide the lifting behind overloadings of <hask>Num</hask> and other classes (as in [http://conal.net/Fran Fran], [http://conal.net/Pan Pan], and other systems). Some methods, however, do not not have sufficiently flexible types (e.g., <hask>(==)</hask>), and the illusion becomes awkward. The <hask>Arrow</hask> and <hask>Applicative</hask> interfaces hide the source types. 

Line 83:  Line 82:  
And use them: 
And use them: 

<haskell> 
<haskell> 

−  ui1x :: UI (Source ()) 
+  ui1x :: UI () 
ui1x = title "Shopping List" $ 
ui1x = title "Shopping List" $ 

do a < apples 
do a < apples 

Line 92:  Line 91:  
We can go pointfree by using <hask>liftM2</hask> and <hask>(>>=)</hask>: 
We can go pointfree by using <hask>liftM2</hask> and <hask>(>>=)</hask>: 

<haskell> 
<haskell> 

+   Sum UIs 

+  infixl 6 .+. 

+  
+  (.+.) :: Num a => UIS a > UIS a > UIS a 

+  (.+.) = liftA2 (liftA2 (+)) 

+  
fruit :: UI (Source Int) 
fruit :: UI (Source Int) 

−  fruit = liftM2 (liftA2 (+)) apples bananas 
+  fruit = apples .+. bananas 
−  ui1y :: UI (Source ()) 
+  ui1y :: UI () 
ui1y = title "Shopping List" $ fruit >>= total 
ui1y = title "Shopping List" $ fruit >>= total 

−  </haskell> 

−  
−  === Arrow === 

−  
−  Using source types allows the monadic style to capture the static nature of the input GUI while giving access to a ''source'' of dynamic values. Alternatively, we can solve the problem by replacing the [[Monad]] abstraction with one that separates static and dynamic aspects. Getting that separation is the point of the [[Arrow]] abstraction, and thus Phooey provides an arrow interface as well. Moreover, the UI arrow is implemented on top of its UI monad using a simple, reusable pattern. See the 

−  [http://darcs.haskell.org/packages/phooey/doc/html/GraphicsUIPhooeyArrow.html Arrow interface doc] 

−  and its [http://darcs.haskell.org/packages/phooey/doc/html/src.Graphics.UI.Phooey.Arrow.hs.html source code]. 

−  
−  The example: 

−  <haskell> 

−  ui1 :: UI () () 

−  ui1 = title "Shopping List" $ 

−  proc () > do 

−  a < title "apples" $ islider (0,10) 3 < () 

−  b < title "bananas" $ islider (0,10) 7 < () 

−  title "total" showDisplay < a+b 

−  </haskell> 

−  Note the simplicity of <hask>a+b</hask>. 

−  
−  The types of <hask>islider</hask>, <hask>showDisplay</hask>, and <hask>title</hask> as as in the monadic version, with these new definitions of input and output widget types: 

−  <haskell> 

−  type IWidget a = a > UI () a 

−  type OWidget a = UI a () 

</haskell> 
</haskell> 

=== Applicative Functor === 
=== Applicative Functor === 

−  [[Applicative functor]]s provide still another approach to separating static and dynamic information. Here is our example, showing just the changes relative to the [[#Monadmonadic]] version. (See the 
+  [[Applicative functor]]s (AFs) provide still another approach to separating static and dynamic information. Here is our example, showing just the changes relative to the [[#Monadmonadic]] version. (See the 
−  [http://darcs.haskell.org/packages/phooey/doc/html/GraphicsUIPhooeyApplicative.html Applicative interface doc] 
+  [http://darcs.haskell.org/packages/phooey/doc/html/GraphicsUIPhooeyApplicative.html Applicative interface doc] and its [http://darcs.haskell.org/packages/phooey/doc/html/src.Graphics.UI.Phooey.Applicative.hs.html source code].) 
−  and its [http://darcs.haskell.org/packages/phooey/doc/html/src.Graphics.UI.Phooey.Applicative.hs.html source code].) 

<haskell> 
<haskell> 

ui1 :: UI (IO ()) 
ui1 :: UI (IO ()) 

Line 136:  Line 118:  
total = title "total" showDisplay 
total = title "total" showDisplay 

</haskell> 
</haskell> 

+  I chose reversed AF application <hask>(<**>)</hask> rather than <hask>(<*>)</hask> so the fruit (argument) would be displayed above the total (function). 

The UIbuilding functions again have the same types as before, relative to these new definitions: 
The UIbuilding functions again have the same types as before, relative to these new definitions: 

Line 150:  Line 133:  
* <hask>ui1</hask> is an IOvalued UI. 
* <hask>ui1</hask> is an IOvalued UI. 

−  == Dynamic bounds == 
+  The applicative UI interface (<hask>Graphics.UI.Phooey.Applicative</hask>) is implemented as a very simple layer on top of the monadic interface, using type composition (from [[TypeCompose]]): 
−  
−  Phooey sliders may have dynamic bounds, taking a ''source'' of bounds instead of static bounds. In the following example, the first two sliders determine the bounds of the third slider. 

−  : [[Image:Ui2.png]] 

−  Of course, one would want a prettier interface, but this example will serve to illustrate a point. 

−  
−  === Dynamic bounds, monad version === 

−  
−  In the Monad version, the new function is 

<haskell> 
<haskell> 

−  isliderDyn :: Source (Int,Int) > IWidget Int 
+  type UI = M.UI `O` Source 
</haskell> 
</haskell> 

−  +  Thanks to properties of <hask>O</hask>, this definition suffices to make <hask>UI</hask> an AF. 

−  Example code: 

−  <haskell> 

−  ui2 :: UI (Source ()) 

−  ui2 = do l < title "lo" $ sl0 3 

−  h < title "hi" $ sl0 8 

−  v < title "val" $ isliderDyn (liftA2 (,) l h) 5 

−  title "factorial" $ showDisplay (liftA fact v) 

−  </haskell> 

−  
−  Factoring: 

−  <haskell> 

−  lo,hi :: UI (Source Int) 

−  lo = title "lo" $ sl0 3 

−  hi = title "hi" $ sl0 8 

−  
−  pair :: Applicative f => f a > f b > f (a,b) 

−  pair = liftA2 (,) 

−  
−  bounds :: UI (Source (Int,Int)) 

−  bounds = liftM2 pair lo hi 

−  
−  val :: UI (Source Int) 

−  val = do b < bounds 

−  title "val" $ isliderDyn b 5 

−  
−  ui2 = do v < val 

−  title "factorial" $ showDisplay (liftA fact v) 

−  </haskell> 

−  
−  As a variation, we might prefer to wrap the "val" title is around the lo & hi sliders as well the val slider. This layout reflects the purpose of the "lo" and "hi" sliders. 

−  : [[Image:Ui2app.png]] 

−  
−  The only change: 

−  <haskell> 

−  val = title "val" $ 

−  do b < bounds 

−  isliderDyn b 5 

−  </haskell> 

−  
−  === Dynamic bounds, arrow version === 

−  
−  Example code: 

−  <haskell> 

−  ui2 = proc () > do 

−  l < lo < () 

−  h < hi < () 

−  v < title "val" $ isliderDyn 5 < (l,h) 

−  title "factorial" showDisplay < fact v 

−  </haskell> 

−  
−  Here's an arrow variation using <hask>isliderDyn</hask> even with static bounds: 

−  <haskell> 

−  ui2 = proc () > do 

−  lo < title "lo" $ isliderDyn 3 < (0,10) 

−  hi < title "hi" $ isliderDyn 8 < (0,10) 

−  val < title "val" $ isliderDyn 5 < (lo,hi) 

−  title "factorial" showDisplay < fact val 

−  </haskell> 

−  
−  We can also do some factoring. The bounds come out very simply: 

−  <haskell> 

−  bounds :: UI () (Int,Int) 

−  bounds = lo &&& hi 

−  </haskell> 

−  
−  Then 

−  <haskell> 

−  val = bounds >>> title "val" (isliderDyn 5) 

−  
−  ui2 = (fact ^<< val') >>> title "factorial" showDisplay 

−  </haskell> 

−  
−  Spelling out <hask>(^<<)</hask>: 

−  <haskell> 

−  ui2 = val >>> pure fact >>> title "factorial" showDisplay 

−  </haskell> 

−  
−  If we want the "val" title around the bounds, redefine <hask>val</hask>: 

−  <haskell> 

−  val = title "val" $ (lo &&& hi) >>> isliderDyn 5 

−  </haskell> 

−  
−  
−  
−  === Dynamic bounds, applicative functor version === 

−  
−  The example code is very simple: 

−  <haskell> 

−  val = title "val" $ isliderDyn (pair lo hi) 5 

−  
−  ui2 = (fact <$> val) <**> title "factorial" showDisplay 

−  </haskell> 

−  
−  This version includes the bounds within the "val" title. I don't know how to get a "val" title on just the dynamicallybounded slider. 

== Layout == 
== Layout == 

−  
By default, UI layout follows the order of the specification, with earlierspecified components above laterspecified ones. This layout may be overridden by explicit layout functions. For instance, the following definitions form variations of <hask>ui1</hask> laid out from bottom to top and from left to right. 
By default, UI layout follows the order of the specification, with earlierspecified components above laterspecified ones. This layout may be overridden by explicit layout functions. For instance, the following definitions form variations of <hask>ui1</hask> laid out from bottom to top and from left to right. 

Line 182:  Line 164:  
</haskell> 
</haskell> 

−  == Recursive GUIs == 
+  == Event Examples == 
−  Next is a recursive example. It is like <hask>ui2</hask>, but the <hask>lo</hask> and <hask>hi</hask> sliders are used to bound each other. The specification enforces the constraint that <hask>lo <= hi</hask>. 
+  The shopping examples above demonstrate the simple case of outputs (<hask>total</hask>) as functions of varying inputs (<hask>apples</hask> and <hask>bananas</hask>). Events were hidden inside the implementation of [[DataDriven#Sourcesource]]s. 
−  : [[Image:Ui4.png]] 
+  This section shows two classic functional GUI examples involving a visible notion of [[DataDriven#Eventevent]]s. 
−  Monad version: 
+  === Counting === 
−  <haskell> 

−  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) 

−  </haskell> 

−  Refactoring, 

−  <haskell> 

−  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) 
+  === Calculator === 
−  unPair p = (fmap fst p, fmap snd p) 

−  </haskell> 

−  Then continue as with <hask>ui1</hask>: 

−  <haskell> 

−  valR :: UI (Source Int) 

−  valR = do b < boundsR 

−  title "val" $ isliderDyn b 5 

−  uir1' = do v < valR 

−  title "factorial" $ showDisplay (liftA fact v) 

−  </haskell> 

−  
−  The next example is tightly recursive. A slider is used to bound ''itself'', so that the range is always the current value ±5. 

−  : [[Image:Ui5.png]] 

−  
−  <haskell> 

−  uir2 = mdo v < title "val" (isliderDyn (liftA (plusMinus 5) v) 6) 

−  title "squared" (showDisplay (liftA square v)) 

−  where 

−  plusMinus n x = (xn,x+n) 

−  square y = y*y 

−  </haskell> 

−  The arrow and applicative functor versions of these examples exhaust stack space. 

== Portability == 
== Portability == 
Revision as of 04:15, 11 September 2007
Contents 
1 Abstract
Warning: The Haddock docs are not ready yet. I'm trying to get a working haddock 2.0 running (on my windows machine).
Phooey is a functional UI library for Haskell. Or it's two of them, as it provides aBesides this wiki page, here are more ways to find out about Phooey:
 Read the Haddock docs (with source code, additional examples, and Comment/Talk links).
 Get the code repository: darcs get http://darcs.haskell.org/packages/phooey, or
 Grab a distribution tarball.
 See the version changes.
Phooey is also used in GuiTV, a library for composable interfaces and "tangible values".
2 Introduction
GUIs are usually programmed in an unnatural style, in that implementation dependencies are inverted, relative to logical dependencies. This reversal results directly from the push (datadriven) orientation of most GUI libraries. While outputs depend on inputs from a user and semantic point of view, the push style imposes an implementation dependence of inputs on outputs.
A second drawback of the push style is that it is imperative rather than declarative. A GUI program describes actions to update a model and and view in reaction to user input. In contrast to the howtoupdate style of an imperative program, a functional GUI program would express whatitis of a model in terms of the inputs and of the view in terms of the model.
The questions of pushvspull and imperativevsdeclarative are related. While an imperative GUI program could certainly be written to pull (poll) values from input to model and model to view, thus eliminating the dependency inversion, I don't know how a declarative program could be written in the inverteddependency style. (Do you?).
A important reason for using push rather than pull in a GUI implementation is that push is typically much more efficient. A simple pull implementation would either waste time recomputing an unchanging model and view (pegging your CPU for no benefit), or deal with the complexity of avoiding that recomputation. The push style computes only when inputs change. (Continuous change, i.e. animation, negates this advantage of push.)
Phooey ("Phunctional ooser ynterfaces") adopts the declarative style, in which outputs are expressed in terms of inputs. Under the hood, however, the implementation is pushbased (datadriven). Phooey uses the DataDriven library to perform the dependency inversion invisibly, so that programmers may express GUIs simply and declaratively while still getting an efficient implementation.
Phooey came out of Pajama and Eros. Pajama is a reimplementation of the Pan language and compiler for function synthesis of interactive, continuous, infinite images. Pan and Pajama use a monadic style for specifying GUIs and are able to do so because they use the implementation trick of Compiling Embedded Languages, in which one manipulates expressions rather than values. (This trick is mostly transparent, but the illusion shows through in places.)
3 One example, two interfaces
As an example, below is a simple shopping list GUI. ThePhooey presents two styles of functional GUI interfaces, structured as a monad and as an applicative functor. (I have removed the original arrow interface.) Below you can see the code for the shopping list example in each of these styles.
The examples below are all found undersrc/Examples/
in the phooey distribution, in the modules Monad.hs
, and Applicative.hs
. In each case, the example is run by loading the corresponding example module into ghci and typing 3.1 Monad
Here is a definition for the GUI shown above, formulated in terms of Phooey's monadic interface. See the monad interface and its source code.
ui1 :: UI () 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)
The relevant library declarations:
 Input widget type (with initial value) type IWidget a = a > UI (Source a)  Output widget type type OWidget a = Source a > UI () islider :: (Int,Int) > IWidget Int showDisplay :: Show a => OWidget a title :: String > UI a > UI a
Before we move on to other interface styles, let's look at some refactorings. First pull out the slider minus initial value:
sl0 :: IWidget Int sl0 = islider (0,10)
Then the titled widgets:
apples, bananas :: UI (Source Int) apples = title "apples" $ sl0 3 bananas = title "bananas" $ sl0 7 total :: Num a => OWidget a total = title "total" . showDisplay
And use them:
ui1x :: UI () ui1x = title "Shopping List" $ do a < apples b < bananas total (liftA2 (+) a b)
 Sum UIs infixl 6 .+. (.+.) :: Num a => UIS a > UIS a > UIS a (.+.) = liftA2 (liftA2 (+)) fruit :: UI (Source Int) fruit = apples .+. bananas ui1y :: UI () ui1y = title "Shopping List" $ fruit >>= total
3.2 Applicative Functor
Applicative functors (AFs) provide still another approach to separating static and dynamic information. Here is our example, showing just the changes relative to the monadic version. (See the Applicative interface doc and its source code.)
ui1 :: UI (IO ()) ui1 = title "Shopping List" $ fruit <**> total fruit :: UI Int fruit = liftA2 (+) apples bananas total :: Num a => OWidget a total = title "total" showDisplay
The UIbuilding functions again have the same types as before, relative to these new definitions:
type IWidget a = a > UI a type OWidget a = UI (a > IO ())
Notes:
 Output widgets are functionvalued UI.
 has a simpler definition, requiring only one lifting instead of two.fruit
 is subtly different, because output widgets are now functionvalued.total
 uses the reverse application operatorui1. This reversal causes the function to appear after (below) the argument.(<**>)
 is an IOvalued UI.ui1
type UI = M.UI `O` Source
4 Layout
By default, UI layout follows the order of the specification, with earlierspecified components above laterspecified ones. This layout may be overridden by explicit layout functions. For instance, the following definitions form variations ofGUIs & code:
uiB1 = fromBottom ui1 uiL1 = fromLeft ui1
ui3 = fromBottom $ title "Shopping List" $ fromRight fruit >>= total
5 Event Examples
The shopping examples above demonstrate the simple case of outputs (This section shows two classic functional GUI examples involving a visible notion of events.
5.1 Counting
5.2 Calculator
6 Portability
Phooey is built on wxHaskell. Quoting from the wxHaskell home page,
wxHaskell is therefore built on top of wxWidgets  a comprehensive C++ library that is portable across all major GUI platforms; including GTK, Windows, X11, and MacOS X.
So I expect that Phooey runs on all of these platforms. That said, I have only tried Phooey on Windows. Please give it a try and leave a message on the talk page.
7 Known problems
 Recursive examples don't work (consumes memory) in the Arrow or Applicative interface.
8 Plans
 Use Javascript and HTML in place wxHaskell, and hook it up with Yhc/Javascript.