Is functional GUI programming possible? [closed]
Asked Answered
S

15

420

I've recently caught the FP bug (trying to learn Haskell), and I've been really impressed with what I've seen so far (first-class functions, lazy evaluation, and all the other goodies). I'm no expert yet, but I've already begun to find it easier to reason "functionally" than imperatively for basic algorithms (and I'm having trouble going back where I have to).

The one area where current FP seems to fall flat, however, is GUI programming. The Haskell approach seems to be to just wrap imperative GUI toolkits (such as GTK+ or wxWidgets) and to use "do" blocks to simulate an imperative style. I haven't used F#, but my understanding is that it does something similar using OOP with .NET classes. Obviously, there's a good reason for this--current GUI programming is all about IO and side effects, so purely functional programming isn't possible with most current frameworks.

My question is, is it possible to have a functional approach to GUI programming? I'm having trouble imagining what this would look like in practice. Does anyone know of any frameworks, experimental or otherwise, that try this sort of thing (or even any frameworks that are designed from the ground up for a functional language)? Or is the solution to just use a hybrid approach, with OOP for the GUI parts and FP for the logic? (I'm just asking out of curiosity--I'd love to think that FP is "the future," but GUI programming seems like a pretty large hole to fill.)

Seena answered 20/4, 2010 at 5:35 Comment(6)
Having looked at GUI's in Common Lisp and OCaml, I would say that, more likely, its Haskell's laziness that's causing the issue.Kassandrakassaraba
@Kassandrakassaraba Common Lisp isn't a functional language though, it works with mutable data and embraces side effectsFleecy
haskell.org/haskellwiki/Functional_Reactive_Programming for a list of GUI librariesDatum
@ElectricCoffee Lisp is an extremely flexible language capable of being used in many different styles, and many people choose to use Lisp in a functional style.Erdman
From my experience (though I'm still trying to believe in it and learning more) FRP really reaches its limit with GUI programming; it's nice and elegant for 80% of the uses cases but rich widgets require very precise control of their internal state (e.g search combo boxes, etc) and FRP just gets in the way. Imperative is not always evil; trying to minimize the amount of imperative code is good but removing 100% of it ? Have yet to see it work for non trivial UI development.Mooch
@ElectricCoffee "Common Lisp isn't a functional language though". Lisp is the mother of all functional languages. You mean Lisp isn't pure.Clitoris
P
189

The Haskell approach seems to be to just wrap imperative GUI toolkits (such as GTK+ or wxWidgets) and to use "do" blocks to simulate an imperative style

That's not really the "Haskell approach" -- that's just how you bind to imperative GUI toolkits most directly -- via an imperative interface. Haskell just happens to have fairly prominent bindings.

There are several moderately mature, or more experimental purely functional/declarative approaches to GUIs, mostly in Haskell, and primarily using functional reactive programming.

Some examples are:

For those of you not familiar with Haskell, Flapjax, http://www.flapjax-lang.org/ is an implementation of functional reactive programming on top of JavaScript.

Pieplant answered 20/4, 2010 at 5:35 Comment(10)
See Conal Elliott's paper about fruit for a great, in-depth description of the technique and the decisions: conal.net/papers/genuinely-functional-guis.pdf I have been doing purely functional GUI programming in this style for a few months now. I LOVE it, it is such a pleasant relief from the spaghetti hell of imperative UI programming, which seems to be worse in this respect than most imperative programming.Amish
Excellent, that's exactly what I was looking for--looks much more interesting than the imperative approaches I've seen (for instance in Real World Haskell). I'll definitely be checking out various FRP libraries.Seena
I 100% agree with this. To make it crystal clear: the reason why existing GUI toolkits are often used is because they exist. The reason why interfaces to them tend to be imperative and impure is because the toolkits tend to be imperative and impure. The reason why the toolkits tend to be imperative and impure is because the operating systems they depend on tend to be imperative and impure. However, there's nothing fundamentally requiring any of these to be impure: there's functional bindings for those toolkits, there's functional toolkits, there are even functional operating systems.Acetone
It's all just a matter of laziness. (Bad pun intended.)Acetone
Someday all GUI design will be implemented via WYSIWYG, with the logic implemented functionally. This is my prediction.Dickens
Jorg: Sounds exciting. Can you give me an example of a functional operating system?Brost
The paper luqui mentions seems to be dead. There is a working link on Conal Elliott's site, though: conal.net/papers/genuinely-functional-guis.pdfTsang
the only one that seems to be "up to date" is reactive-bananaDalpe
@BlueRaja-DannyPflughoeft Delphi and FoxPro came pretty close, and there's been quite a few declarative approaches to web programming (HTML and CSS are declarative by nature, some server and client frameworks fit well into that, some just drop back to the imperative style). The approach seems to go in and out of favour periodically with what people consider cool at the moment :)Originate
I have corrected luqui's link. May clean up some of these comments later. Probably best if someone edits relevant links into the post and flags the comments for obsolescence.Mccurry
C
76

My question is, is it possible to have a functional approach to GUI programming?

The key words you are looking for are "functional reactive programming" (FRP).

Conal Elliott and some others have made a bit of a cottage industry out of trying to find the right abstraction for FRP. There are several implementations of FRP concepts in Haskell.

You might consider starting with Conal's most recent "Push-Pull Functional Reactive Programming" paper, but there are several other (older) implementations, some linked from the haskell.org site. Conal has a knack for covering the entire domain, and his paper can be read without reference to what came before.

To get a feel for how this approach can be used for GUI development, you might want to look at Fudgets, which while it is getting a bit long in the tooth these days, being designed in the mid 90s, does present a solid FRP approach to GUI design.

Contraindicate answered 20/4, 2010 at 5:35 Comment(1)
I'd like to add the rise of usage of "Reactive Extensions" (FRP Libraries; however, not FP) which was originally written for C# and then ported to Java (RxJava) and JavaScript (RxJS) and various languages. Check out reactivex.ioAt the point, Angular 2 makes extensive use of RxJS.Dallis
P
63

Windows Presentation Foundation is a proof that functional approach works very well for GUI programming. It has many functional aspects and "good" WPF code (search for MVVM pattern) emphasizes the functional approach over imperative. I could bravely claim that WPF is the most successful real-world functional GUI toolkit :-)

WPF describes the User interface in XAML (although you can rewrite it to functionally looking C# or F# too), so to create some user interface you would write:

<!-- Declarative user interface in WPF and XAML --> 
<Canvas Background="Black">
   <Ellipse x:Name="greenEllipse" Width="75" Height="75" 
      Canvas.Left="0" Canvas.Top="0" Fill="LightGreen" />
</Canvas>

Moreover, WPF also allows you to declaratively describe animations and reactions to events using another set of declarative tags (again, same thing can be written as C#/F# code):

<DoubleAnimation
   Storyboard.TargetName="greenEllipse" 
   Storyboard.TargetProperty="(Canvas.Left)"
   From="0.0" To="100.0" Duration="0:0:5" />

In fact, I think that WPF has many things in common with Haskell's FRP (though I believe that WPF designers didn't know about FRP and it is a bit unfortunate - WPF sometimes feels a bit weird and unclear if you're using the functional point of view).

Prase answered 20/4, 2010 at 5:35 Comment(3)
While XAML is very declarative in nature, does MVVM really encourage a functional style of programming? The whole notion of a view model, whose job is to track the state of the view (and implements an interface called INotifyPropertyChanged of all things), seems antithetical to FP to me. I'm definitely no expert on FP, and maybe I'm focusing too much on the immutability aspect as opposed to the declarative aspect, but I'm having trouble seeing how the MVVM pattern (as typically used) is an example of FP.Quarrel
@Quarrel I would argue that it does. I don't think anyone would realistically use FP for strict immutable code. Instead, you decide where your mutability boundaries are, and work immutable on all the other levels - in this case, everyone can assume the state is immutable, except for that single tiny part that actually mutates the state. It's similar to how HTML works - yeah, you've got the immutable DOM, but whenever you navigate, you still have to build a new one. INotifyPropertyChanged is just an update function you pass to wherever you need to handle the GUI updates - it's a latency fix.Originate
Steven Pemberton wrote 2 great posts on F# and WPF, his Thoughts on WPF development with F# towards the end of the second post adds to this discussion. 2 other examples that also intrigued me were the use of a functional controller in event driven MVVM and the use of discriminated unions and recursion for constructing a simple interface in the WPF controls demo by Flying Frog Consultancy.Proboscidean
P
29

I would actually say that functional programming (F#) is much better tool for user interface programming than for example C#. You just need to think about the problem a little bit differently.

I discuss this topic in my functional programming book in Chapter 16, but there is a free excerpt available, which shows (IMHO) the most interesting pattern that you can use in F#. Say you want to implement drawing of rectangles (user pushes the button, moves the mouse and releases the button). In F#, you can write something like this:

let rec drawingLoop(clr, from) = async { 
   // Wait for the first MouseMove occurrence 
   let! move = Async.AwaitObservable(form.MouseMove) 
   if (move.Button &&& MouseButtons.Left) = MouseButtons.Left then 
      // Refresh the window & continue looping 
      drawRectangle(clr, from, (move.X, move.Y)) 
      return! drawingLoop(clr, from) 
   else
      // Return the end position of rectangle 
      return (move.X, move.Y) } 

let waitingLoop() = async { 
   while true do
      // Wait until the user starts drawing next rectangle
      let! down = Async.AwaitObservable(form.MouseDown) 
      let downPos = (down.X, down.Y) 
      if (down.Button &&& MouseButtons.Left) = MouseButtons.Left then 
         // Wait for the end point of the rectangle
         let! upPos = drawingLoop(Color.IndianRed, downPos) 
         do printfn "Drawn rectangle (%A, %A)" downPos upPos }

This is a very imperative approach (in the usual pragmatic F# style), but it avoids using mutable state for storing the current state of drawing and for storing inital location. It can be made even more functional though, I wrote a library that does that as part of my Master thesis, which should be available on my blog in the next couple of days.

Functional Reactive Programming is a more functional approach, but I find it somewhat harder to use as it relies on quite advanced Haskell features (such as arrows). However, it is very elegant in a large number of cases. It's limitation is that you cannot easily encode a state machine (which is a useful mental model for reactive programs). This is very easy using the F# technique above.

Prase answered 20/4, 2010 at 5:35 Comment(3)
+1 This reflects our experience, having written several production GUIs in F# using combinator libraries and IObservable.Clitoris
Has the comment on FRP changed since the introduction of reactive extensions to the .NET library?Deadeye
Here's some research on Arrowized FRP and how effects and mutation can be embedded within Arrowized FRP without breaking the laws: haskell.cs.yale.edu/wp-content/uploads/2015/10/… (btw most FRP libraries use Monads or even Applicatives, so it's not correct that Arrows are required).Schnabel
M
17

Whether you're in a hybrid functional/OO language like F# or OCaml, or in a purely functional language like Haskell where side-effects are relegated to the IO monad, it's mostly the case that a ton of the work required to manage a GUI is much more like a "side effect" than like a purely functional algorithm.

That said, there has been some really solid research put into functional GUIs. There are even some (mostly) functional toolkits such as Fudgets or FranTk.

Manriquez answered 20/4, 2010 at 5:35 Comment(1)
"functional GUIs" link broken :( cached: webcache.googleusercontent.com/search?q=cache:http://…Hagy
S
15

You might check out the series by Don Syme on F# where he demo's creating a gui. the following link is to third part of the series (you can link from there to the other two parts).

Using F# for WPF development would be a very interesting GUI paradigm...

http://channel9.msdn.com/shows/Going+Deep/C9-Lectures-Dr-Don-Syme-Introduction-to-F-3-of-3/

Sandlin answered 20/4, 2010 at 5:35 Comment(0)
R
12

One of mind-opening ideas behind Functional Reactive Programming is to have an event handling function producing BOTH reaction to events AND the next event handling function. Thus an evolving system is represented as a sequence of event handling functions.

For me, learning of Yampa became a crucial poing to get that functions-producing-functions thing properly. There are some nice papers about Yampa. I recommend The Yampa Arcade:

http://www.cs.nott.ac.uk/~nhn/Talks/HW2003-YampaArcade.pdf (slides, PDF) http://www.cs.nott.ac.uk/~nhn/Publications/hw2003.pdf (full article, PDF)

There is a wiki page on Yampa at Haskell.org

http://www.haskell.org/haskellwiki/Yampa

Original Yampa home page:

http://www.haskell.org/yampa (unfortunately is broken at the moment)

Rh answered 20/4, 2010 at 5:35 Comment(1)
That link is broken for a long time. Try this YampaEcg
F
9

Since this question was first asked, functional reactive programming has been made a bit more mainstream by Elm.

I suggest checking it out at http://elm-lang.org , which also has some truly excellent interactive tutorials on how to make a fully functional in-browser GUI.

It allows you to make fully functional GUI's where the code you need to supply yourself consists only of pure functions. I personally found it a lot easier to get into than the various Haskell GUI frameworks.

Frierson answered 20/4, 2010 at 5:35 Comment(1)
Here's the original FRP thesis behind Elm. But also since May 2016 Elm isn't a FRP language anymore.Jingo
X
6

Elliot's talk on FRP can be found here.

In addition, not really an answer but a remark and a few thoughts: somehow the term "functional GUI" seems a little bit like an oxymoron (pureness and IO in the same term).

But my vague understanding is that functional GUI programming is about declaratively defining a time dependent function that takes the (real)time dependent user input and produces time dependent GUI output.

In other words, this function is defined like a differential equation declaratively, instead of by an algorithm imperatively using mutable state.

So in conventional FP one uses time independent functions, while in FRP one uses time dependent functions as building blocks for describing a program.

Let us think about simulating a ball on a spring with which the user can interact. The ball's position is the graphical output (on the screen), user pushing the ball is a keypress (input).

Describing this simulation program in FRP (according to my understanding) is done by a single differential equation (declaratively): acceleration * mass = - stretch of spring * spring constant + Force exerted by the user.

Here is a video on ELM that illustrates this viewpoint.

Xanthin answered 20/4, 2010 at 5:35 Comment(0)
S
5

As of 2016, there are several more, relatively mature FRP frameworks for Haskell such as Sodium and Reflex (but also Netwire).

The Manning book on Functional Reactive Programming showcases the Java version of Sodium, for working examples, and illustrates how an FRP GUI code base behaves and scales in comparison to imperative as well as Actor based approaches.

There's also a recent paper on Arrowized FRP and the prospect of incorporating side effects, IO and mutation in a law abiding, pure FRP setting: http://haskell.cs.yale.edu/wp-content/uploads/2015/10/dwc-yale-formatted-dissertation.pdf.

Also worth noting is that JavaScript frameworks such as ReactJS and Angular and many others either already are or are moving towards using an FRP or otherwise functional approach to achieving scalable and composable GUI components.

Schnabel answered 20/4, 2010 at 5:35 Comment(1)
Sodium has been deprecated in favor of reactive banana according to Sodium's github readmeGlutathione
S
4

Markup languages like XUL allow you to build a GUI in a declarative way.

Spirograph answered 20/4, 2010 at 5:35 Comment(0)
J
3

To address this I posted some thoughts of mine in using F#,

http://fadsworld.wordpress.com/2011/04/13/f-in-the-enterprise-i/ http://fadsworld.wordpress.com/2011/04/17/fin-the-enterprise-ii-2/

I'm also planning to do a video tutorial to finish up the series and show how F# can contribute in UX programming.

I'm only talking in context of F# here.

-Fahad

Jube answered 20/4, 2010 at 5:35 Comment(0)
C
2

All these other answers are built up upon functional programming, but make a lot of their own design decisions. One library that is built basically entirely out of functions and simple abstract data types is gloss. Here is the type for its play function from the source

-- | Play a game in a window. Like `simulate`, but you manage your own input events.
play    :: Display              -- ^ Display mode.
        -> Color                -- ^ Background color.
        -> Int                  -- ^ Number of simulation steps to take for each second of real time.
        -> world                -- ^ The initial world.
        -> (world -> Picture)   -- ^ A function to convert the world a picture.
        -> (Event -> world -> world)    
                -- ^ A function to handle input events.
        -> (Float -> world -> world)
                -- ^ A function to step the world one iteration.
                --   It is passed the period of time (in seconds) needing to be advanced.
        -> IO ()

As you can see, it works entirely by supplying pure functions with simple abstract types, that other libraries help you with.

Cognate answered 20/4, 2010 at 5:35 Comment(0)
C
1

The most apparent innovation noticed by people new to Haskell is that there is a separation between the impure world that is concerned with communicating with the outside world, and the pure world of computation and algorithms. A frequent beginner question is "How can I get rid of IO, i.e., convert IO a into a?" The way to to it is to use monads (or other abstractions) to write code that performs IO and chains effects. This code gathers data from the outside world, creates a model of it, does some computation, possibly by employing pure code, and outputs the result.

As far as the above model is concerned, I don't see anything terribly wrong with manipulating GUIs in the IO monad. The largest problem that arises from this style is that modules are not composable anymore, i.e., I lose most of my knowledge about the global execution order of statements in my program. To recover it, I have to apply similar reasoning as in concurrent, imperative GUI code. Meanwhile, for impure, non-GUI code the execution order is obvious because of the definition of the IO monad's >== operator (at least as long as there is only one thread). For pure code, it doesn't matter at all, except in corner cases to increase performance or to avoid evaluations resulting in .

The largest philosophical difference between console and graphical IO is that programs implementing the former are usually written in synchronous style. This is possible because there is (leaving aside signals and other open file descriptors) just one source of events: the byte stream commonly called stdin. GUIs are inherently asynchronous though, and have to react to keyboard events and mouse clicks.

A popular philosophy of doing asynchronous IO in a functional way is called Functional Reactive Programming (FRP). It got a lot of traction recently in impure, non-functional languages thanks to libraries such as ReactiveX, and frameworks such as Elm. In a nutshell, it's like viewing GUI elements and other things (such as files, clocks, alarms, keyboard, mouse) as event sources, called "observables", that emit streams of events. These events are combined using familiar operators such as map, foldl, zip, filter, concat, join, etc., to produce new streams. This is useful because the program state itself can be seen as scanl . map reactToEvents $ zipN <eventStreams> of the program, where N is equal to the number of observables ever considered by the program.

Working with FRP observables makes it possible to recover composability because events in a stream are ordered in time. The reason is that the event stream abstraction makes it possible to view all observables as black boxes. Ultimately, combining event streams using operators gives back some local ordering on execution. This forces me to be much more honest about which invariants my program actually relies on, similar to the way that all functions in Haskell have to be referentially transparent: if I want to pull data from another part of my program, I have to be explicit ad declare an appropriate type for my functions. (The IO monad, being a Domain-Specific language for writing impure code, effectively circumvents this)

Clinkstone answered 20/4, 2010 at 5:35 Comment(0)
P
-23

Functional programming may have moved on from when I was at university, but as I recall the main point of a functional programming system was to stop the programmer creating any “side effect”. However users buy software due to the side effects that are created, e.g. updating a UI.

Primulaceous answered 20/4, 2010 at 5:35 Comment(1)
I think you misunderstood the point: it's not that functional programming has no outside effect on the world--that would make all programs entirely useless! Rather, functional programming lets you quarantine the IO so you know which bits use it and which bits don't.Interdisciplinary

© 2022 - 2024 — McMap. All rights reserved.