Phooey

From HaskellWiki
Revision as of 20:01, 16 January 2007 by Conal (talk | contribs) (→‎Motivation)
Jump to navigation Jump to search

Phooey is an [arrow]-based functional UI library for [Haskell].

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 imperative orientation of most GUI libraries. While outputs depend on inputs from a user and semantic point of view, the imperative approach imposes an implementation dependence of inputs on outputs.

Phooey ("Phunctional ooser ynterfaces") retains the functional style, in which outputs are expressed in terms of inputs. In addition, Phooey supports dynamic input bounds, flexible layout, and mutually-referential widgets.

As an example, below is a simple shopping list GUI. The total displayed at the bottom of the window always shows the sum of the values of the apples and bananas input sliders. When a user changes the inputs, the output updates accordingly.

ui1.png

Phooey is structured as an arrow, and this example uses arrow notation. The code:

ui1 :: UI () ()
ui1 = title "Shopping List" $
      proc () -> do
	a <- title "apples"  (islider 3) -< (0,10)
	b <- title "bananas" (islider 7) -< (0,10)
	title "total" showDisplay        -< a+b

There are more examples in the Haddock docs.

Motivation

Phooey came out of Pajama, which is a re-implementation 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.)

Switching from expressions to values raises a challenge for a declarative monadic approach. For instance, consider this (problematic) monadic UI.

factOopsUI :: UIM ()
factOopsUI =  do n  <- title "n"   (islider 3 (0,20))
                 title "factorial" (showDisplay (fact n))

If n :: Int, then the second half of the GUI depends on the dynamic run-time values flowing out of the first half, and so must be constructed for each new value of n. The problem is a failure to separate a GUI into its static and dynamic parts. A solution with the monadic framework would be to give n a different type, such as Source Int, which captures the static nature of the input GUI while giving access to a source of dynamic values. Phooey provides this monadic solution in its MonadUI module. The awkwardness is that we can no longer use such simple formulations as factOopsUI above, since expressions like product [1..n] won't type-check. (We can play overloading tricks as in Fran, Pan, and Pajama, but they don't always work.) Instead, we could use return, liftM, liftM2, etc.

factUI :: UIM ()
factUI =  do n  <- title "n"   (islider 3 (return (0,20)))
             title "factorial" (showDisplay (liftM fact n))

Rather than introducing the complexity of the Source type and the need for explicit lifting, 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's primary interface is formulated as an arrow rather than a monad. Phooey's UI arrow is implemented on top of its UI monad using a simple, reusable pattern. See the ArrowUI module doc and its source code.

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 ("Discuss this page").