Wednesday, April 18, 2018

A very long Haskell type

For GUI programming I've migrated from the gtk2hs library to the gi-gtk library. This uses overloaded labels to access the properties of GTK3 objects.

I wanted a function which would set the background and foreground colours of a widget. Rather than simply have it modify the object I decided to have it return a list of property setters. It looks like this (the function "contrastText" just returns either white or black):

setColour c = do
      bg <- colourToRGBA c
      fg <- colourToRGBA $ contrastText c
      return [#backgroundRgba := bg, #foregroundRgba := fg]


However when I couldn't get it to type-check I asked ghci what the type should be. Here is the reply!

> :type setColour
setColour
  :: (Data.GI.Base.Attributes.AttrOpIsAllowed
        tag
        (Data.GI.Base.Attributes.AttrAllowedOps
           (Data.GI.Base.Overloading.FindElement
              "foregroundRgba"
              (Data.GI.Base.Overloading.AttributeList obj)
              (((('GHC.TypeLits.Text "Unknown attribute \8216"
                  'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "foregroundRgba")
                 'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
                'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217.")))
        (Data.GI.Base.Attributes.AttrLabel
           (Data.GI.Base.Overloading.FindElement
              "foregroundRgba"
              (Data.GI.Base.Overloading.AttributeList obj)
              (((('GHC.TypeLits.Text "Unknown attribute \8216"
                  'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "foregroundRgba")
                 'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
                'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217.")))
        (Data.GI.Base.Attributes.AttrOrigin
           (Data.GI.Base.Overloading.FindElement
              "foregroundRgba"
              (Data.GI.Base.Overloading.AttributeList obj)
              (((('GHC.TypeLits.Text "Unknown attribute \8216"
                  'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "foregroundRgba")
                 'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
                'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217.")))
        obj
      ~
      'Data.GI.Base.Attributes.OpIsAllowed,
      Data.GI.Base.Attributes.AttrOpIsAllowed
        tag
        (Data.GI.Base.Attributes.AttrAllowedOps
           (Data.GI.Base.Overloading.FindElement
              "backgroundRgba"
              (Data.GI.Base.Overloading.AttributeList obj)
              (((('GHC.TypeLits.Text "Unknown attribute \8216"
                  'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "backgroundRgba")
                 'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
                'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217.")))
        (Data.GI.Base.Attributes.AttrLabel
           (Data.GI.Base.Overloading.FindElement
              "backgroundRgba"
              (Data.GI.Base.Overloading.AttributeList obj)
              (((('GHC.TypeLits.Text "Unknown attribute \8216"
                  'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "backgroundRgba")
                 'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
                'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217.")))
        (Data.GI.Base.Attributes.AttrOrigin
           (Data.GI.Base.Overloading.FindElement
              "backgroundRgba"
              (Data.GI.Base.Overloading.AttributeList obj)
              (((('GHC.TypeLits.Text "Unknown attribute \8216"
                  'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "backgroundRgba")
                 'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
                'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217.")))
        obj
      ~
      'Data.GI.Base.Attributes.OpIsAllowed,
      Data.GI.Base.Attributes.AttrInfo
        (Data.GI.Base.Overloading.FindElement
           "foregroundRgba"
           (Data.GI.Base.Overloading.AttributeList obj)
           (((('GHC.TypeLits.Text "Unknown attribute \8216"
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "foregroundRgba")
              'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
             'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
            'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217.")),
      Data.GI.Base.Attributes.AttrInfo
        (Data.GI.Base.Overloading.FindElement
           "backgroundRgba"
           (Data.GI.Base.Overloading.AttributeList obj)
           (((('GHC.TypeLits.Text "Unknown attribute \8216"
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "backgroundRgba")
              'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
             'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
            'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217.")),
      Control.Monad.IO.Class.MonadIO m,
      Data.GI.Base.Overloading.HasAttributeList obj,
      Data.GI.Base.Attributes.AttrBaseTypeConstraint
        (Data.GI.Base.Overloading.FindElement
           "backgroundRgba"
           (Data.GI.Base.Overloading.AttributeList obj)
           (((('GHC.TypeLits.Text "Unknown attribute \8216"
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "backgroundRgba")
              'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
             'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
            'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217."))
        obj,
      Data.GI.Base.Attributes.AttrSetTypeConstraint
        (Data.GI.Base.Overloading.FindElement
           "backgroundRgba"
           (Data.GI.Base.Overloading.AttributeList obj)
           (((('GHC.TypeLits.Text "Unknown attribute \8216"
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "backgroundRgba")
              'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
             'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
            'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217."))
        GI.Gdk.Structs.RGBA.RGBA,
      Data.GI.Base.Attributes.AttrBaseTypeConstraint
        (Data.GI.Base.Overloading.FindElement
           "foregroundRgba"
           (Data.GI.Base.Overloading.AttributeList obj)
           (((('GHC.TypeLits.Text "Unknown attribute \8216"
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "foregroundRgba")
              'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
             'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
            'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217."))
        obj,
      Data.GI.Base.Attributes.AttrSetTypeConstraint
        (Data.GI.Base.Overloading.FindElement
           "foregroundRgba"
           (Data.GI.Base.Overloading.AttributeList obj)
           (((('GHC.TypeLits.Text "Unknown attribute \8216"
               'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "foregroundRgba")
              'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217 for object \8216")
             'GHC.TypeLits.:<>: 'GHC.TypeLits.ShowType obj)
            'GHC.TypeLits.:<>: 'GHC.TypeLits.Text "\8217."))
        GI.Gdk.Structs.RGBA.RGBA) =>
     Reactive.Banana.Common.Colour
     -> m [Data.GI.Base.Attributes.AttrOp obj tag]


Saturday, March 24, 2018

Why I don’t believe in the Second Amendment (and neither do you or the Supreme Court)


The second amendment says:
A well regulated Militia, being necessary to the security of a free State, the right of the people to keep and bear Arms, shall not be infringed.
This consists of two parts, the preamble “A well regulated Militia, being necessary to the security of a free State” and the effective part “the right of the people to keep and bear Arms, shall not be infringed”.
The meaning of the effective part is very straightforward: “arms” means any kind of weapon. A bowie knife is “arms”, and during the Cold War the superpowers engaged in “Strategic Arms Limitations Talks” (SALT). Although military technology has changed beyond all recognition, the use of the word “arms” to mean any kind of weapon has not changed since 1791 when the Bill of Rights was ratified. Had James Madison and the other framers of the constitution been shown the modern world they would have had no hesitation in agreeing that any form of modern weaponry from a bowie knife to a nuke was included in the definition.

So it would seem that anyone in the United States of America has the constitutional right to purchase, say, a shoulder launched surface to air missile, and to bear that armament anywhere they wish, such as near the end of a runway where large passenger jets are taking off. That would not be a good idea. If military weapons were widely available then they would be used for mass murder of unarmed civilian targets. Stephen Paddock, the Las Vegas shooter, seems to have set out to kill as many people as possible, and he managed to kill 58. An Airbus A-380 typically has a maximum capacity of 525 plus crew, and if one were bought down over the right bit of city then the body count could go into the thousands. Given the opportunity Paddock would surely have done so, and he is not unique.

The Courts

Today the original intent of the Second Amendment is dead as a matter of established law. It is not legal for anyone within the United States to make or buy heavy weapons except under the most stringent and careful of controls.

This would have surprised and disappointed the framers. They had just fought a war in which ordinary armed citizens had beaten off the professional British army. The framers saw this as an important lesson; the liberty of their new nation would be assured by having an armed citizenry who could be relied upon to form a militia and fight against any future tyrant, foreign or domestic. This is what the preamble part of the Second Amendment is about.

I haven’t been able to find any case in which the constitutionality of this ban on heavy weapons has ever been truly tested. However the courts have found that bans on semi-automatic rifles and the carrying of handguns in public are constitutional, and the Supreme Court has declined to review these decisions.

In the case of the Maryland ban on assault rifles, the 4th Circuit Court of Appeals decided 10-4 that the ban was constitutional. The judgement explains this withPut simply, we have no power to extend Second Amendment protections to weapons of war”. The framers of the constitution would have found that bizzare; to them the Second Amendment was precisely about weapons of war.

On the other hand back in 1939 in the Miller case the Supreme Court decided that a sawn-off shotgun was not protected by the Second Amendment because it was not potentially a military weapon, and this is still a valid precedent (they may have been wrong about the military use of sawn-off shotguns in particular, but the principle still stands). So the 4th Circuit has decided that military weapons are unprotected, and the Supreme Court has decided that non-military weapons are unprotected. According to these precedents it would seem that Americans have the constitutional right to keep and bear arms, except for military weapons and non-military weapons.

Self Defense

The most recent case on the Second Amendment that reached the Supreme Court was District of Columbia v Heller in 2008, which was about the constitutionality of a ban on handguns and a requirement that larger guns be kept unloaded and locked. The Court found 5-4 that this ban violated the Second Amendment.

The Heller case was about restrictions on small arms rather than heavy weapons, and the decision is rightly focussed on that. So the question of whether it is constitutional to own heavy weapons was not directly considered. However if the Court had found that small arms are protected by the plain meaning of the Second Amendment, then someone would have used this to challenge laws banning heavy weapons on the grounds that they are equally protected by the Second Amendment. So to overturn the handgun ban the Court had to do two things. First, they had to ignore the plain meaning of the words they were analysing, and second they had to find some other right to keep small arms.
They managed the first part by finding that the Second Amendment is not an unlimited right. They dispose of this in one brief paragraph:

Like most rights, the Second Amendment right is not unlimited. It is not a right to keep and carry any weapon whatsoever in any manner whatsoever and for whatever purpose: For example, concealed weapons prohibitions have been upheld under the Amendment or state analogues. The Court’s opinion should not be taken to cast doubt on longstanding prohibitions on the possession of firearms by felons and the mentally ill, or laws forbidding the carrying of firearms in sensitive places such as schools and government buildings, or laws imposing conditions and qualifications on the commercial sale of arms. Miller’s holding that the sorts of weapons protected are those “in common use at the time” finds support in the historical tradition of prohibiting the carrying of dangerous and unusual weapons.

It is true that, as with other parts of the Bill of Rights, the government can restrict the scope of a right where it has a pressing need to do so. Thus, for instance the First Amendment has at various times been limited to exclude the publication of libel, copyright infringement, certain secrets, and various kinds of pornography. However the scope of First Amendment restrictions has only rarely been allowed to extend beyond those areas. The only significant case in modern times was the Sedition Act of 1918, which the Supreme Court found constitutional the following year. However this is now considered to be a mistake; today the heart of the First Amendment is seen as political speech and any speech touching on politics enjoys the highest level of constitutional protection. The framers of the Constitution would surely agree that this is the proper state of affairs.

However the restrictions on the right to keep and bear arms are not so limited. The Second Amendment is primarily about military weapons, but under federal law today only weapons of little military use may be legally held by civilians. Imagine if the First Amendment were restricted to stating opinions that are in "common use", with citizens only allowed to comment on local politics and speech on state and national affairs being restricted to those government officials employed to do so. That would not be freedom of speech as it is understood in most of the world; indeed it would resemble many dicatorships.

So having found that the Second Amendment does not in fact protect the right to keep and bear most arms, the Supreme Court in 2008 had to find a right that protected handguns. They found this in the right to self defense.

Unlike the right to keep and bear arms, the right to self defense is not enumerated in the Bill of Rights. This is not a problem because the Ninth Amendment specifically says that this “shall not be construed to deny or disparage others retained by the people”. Anyone being attacked has the right to defend themselves with whatever means may be at hand; if you are faced with an attacker then you may pick up a golf club and swing at their head, or try to stab them with a kitchen knife, or just use your fists. The question in such cases is not whether the weapon is legal but whether it is used in a legitimate act of self defense. The same argument applies to guns; if you are forced to defend yourself then using a gun is as reasonable as using a knife, even if that gun was not one you were legally permitted to have.

However in Heller the Supreme Court, after exhaustive analysis of the history of self defense law in both the United States and the United Kingdom, concluded that the right to self defense included the right to keep a hand gun in your house for that purpose.

As an aside, I should say that some state constitutions provide a right to bear arms in self defense. Obviously in those states the situation is different, but this post is about the US constitution.

I’m not going to go any further into this question of personal self defense because this essay is not about that; its about the Second Amendment. Heller is not about the general right to keep and bear arms, its about the right to keep a hand gun as self defense against home invasions. The fact that the Supreme Court found it necessary to invoke a different right to protect hand guns shows that they don’t believe in the Second Amendment either; they actually upheld something different.

The NRA Version of the Second Amendment

The original purpose of the Second Amendment was not individual defense against home invasion, it was collective defense against tyranny. Despite a long consideration of the “well regulated militia” the Heller decision is silent on this question.

Supporters of the NRA are not silent on this question; when asked to justify the right to keep and bear small arms they claim that their guns are a bulwark against government over-reach. Some go so far as to claim that overturning the Second Amendment is the first step in a deep and dark plot to overthrow the rest of the Bill of Rights and institute a socialist tyranny.

However the historical facts do not support the NRA rhetoric on this. Since 1776 the US government has been responsible for a long and sad list of human rights violations, but civilian firearms have never prevented any of them. The last century alone saw the following:
In all of this list civilian guns were never used to defend the rights of anyone. In the few cases where civilian guns appeared, such as Jim Crow lynch mobs, they were on the wrong side.

Has there ever been a case where guns held by civilians were effective in preventing a violation of constituional rights? I doubt it. The fact is that if the American government decides to act in violation of the constitution then there is nothing that a small band of gun owners can do to stop them. The government can always bring in bigger guns and more of them. Various small bands have tried to defy the government; it always ends badly. Today the only ways to change the way the American government behaves are the ballot box, the courts, and bribery making political donations. Pointing guns at government employees will simply get you shot.

Edit:  This Stack Exchange question  points to the Wounded Knee incident in 1973, which was indeed a case where civilians with guns prevented the infringement of constitutional rights by the government. Another answer to the same question also cited the Bundy standoff of 2014 and the related Malheur occupation of 2016, but they are not good examples. The Bundy standoff seems to have been driven by Cliven Bundy's fringe beliefs about federal land ownership rather than a real infringement of constitutional rights, and the Malheur occupation ended with the shooting of one participant and the arrest of everyone else.

The Second Amendment Today

The Bill of Rights was written at a time when there was little difference between military and civilian firearms, military ships were in civilian hands (“privateers”), and the fastest means of communication was a rider on horseback. Firearms were mostly muzzle-loading flintlocks; a skilled gunman might get off two or three rounds per minute and for an individual they were effectively single-shot weapons. They were also not very accurate. Effective use of such weapons required collective action to keep the enemy at bay while you reloaded. The only thing bigger than a rifle was a cannon, which was also muzzle loading and inaccurate.

Today the scope of military weapons has expanded along with the rest of our technology. If the Second Amendment were taken at face value today then many high explosive ranged weapons capable of major destruction would be within the financial reach of much of the population. I opened this essay by inviting you to consider a shoulder launched surface to air missile. I’d like to close by inviting you to consider a school shooter with a bazooka firing a white phosphorus munition.

Most of the Bill of Rights has fared surprisingly well with time; the First Amendment right to free speech now applies to film, television, web sites and computer software, but the basic principle is still the same. This is equally true of Amendments 3 to 10. The Second stands out as a product of its time, overtaken by changes in technology and society.

If you truly believe in the Second Amendment then you believe that any military weapon held by the armed forces of the United States should also be legally available to most civilians. I think the number of people who really believe that is very small. Even the National Rifle Association only believes in the right to keep rifles. There is no National Bazooka Association (actually that’s not true, but it seems to be only one person and may just be a joke).



Sunday, February 25, 2018

Haskell with Reactive Banana and GTK3

I've been doing some GUI coding recently using a combination of Reactive Banana and GTK3. I started out with just GTK3, but I could see it wasn't going to scale because everything GTK3 does is in the IO monad. I found I was having to create IORefs to track the application state, and then pass these around for reading and writing by various event handlers. While the application was small this was manageable, but I could see that it was going to grow into a pile of imperative spaghetti as time went on.

I knew about functional reactive programming (FRP), and went on the hunt for a framework that would work with GTK3. I chose Reactive Banana despite the silly name because it seemed to be targeted at desktop GUI applications rather than games and simulations.

Connecting to GTK3

FRP is based around two key abstractions:

  • Events are instants in time that carry some data. When the user clicks on a button in a GUI you want an event to denote the fact that the button was clicked. If the user moves a slider then you want an event with the new position of the slider.

  • Behaviors carry data that changes over time. In theory this change can be continuous; for instance if you simulate a bouncing ball then the position of the ball is a behavior; at any point in time you can query it, and queries at different times will get different answers. However Reactive Banana only supports behaviors that change in response to events and remain constant the rest of the time. Thats fine: my application responds to user events and doesn't need continuous changes. Take the slider event I mentioned above: when the user moves the slider you want to update a sliderPosition behavior with the latest position so that other parts of the program can then use the value later on.

In Reactive Banana you can convert an event into a behavior with the "stepper" function. You can also get an event back when a behavior changes

Behaviors are a lot like the IORefs I was already using, but events are what make the whole thing scalable. In a large application you may want several things to happen when the user clicks something, but without the Event abstraction all of those things have to directly associated. This harms modularity because it creates dependencies between modules that own callbacks and modules that own widgets, and also causes uncertainty within callbacks about which other callbacks might already have been invoked. With FRP the widget creator can just return an Event without needing to know who receives it, and behaviours are not updated until all events have been executed.

There is already a binding between Reactive Banana and WxHaskell, but nothing for GTK. So my first job was to figure this out. Fortunately it turned out to be very simple. Every widget in GTK3 has three key lists of things in its API:

  • IO functions. These are used to create widgets, and also to get and set various parameters. So for instance the slider widget has functions like this (I'm glossing over some typeclass stuff here. For now just take it that a slider has type Range):

       rangeGetValue :: Range -> IO Double
       rangeSetValue :: Range -> Double -> IO ()

  • Attributes. These are kind of like lenses on the widget, in that they let you both read and write a value. However unlike Haskell lenses this only works in the IO monad. So for instance the slider widget has an attribute:

       rangeValue :: Attr Range Double

    You can access the attributes of a widget using the get and set functions. This is equivalent to using the two IO functions above.

  • Signals. These are hooks where you can attach a callback to a widget using the on function. A callback is an IO monad action which is invoked whenever the signal is triggered. This is usually when the user does something, but can also be when the program does something. For instance the slider widget has a signal

       valueChanged :: Signal Range (IO ())
    The last argument is the type of the callback. In this case it takes no parameters and returns no value, so you can hook into it like this:
       on mySlider valueChanged $ do
          v <- rangeGetValue mySlider

One subtlety about GTK3 signals is that they are often only triggered when the underlying value actually changes, rather than every time the underlying setter function is called. So if the slider is on 10 and you call "rangeSetValue 9" then the callback is triggered in exactly the same way as when the user moves it. However if you call "rangeSetValue 10" then the callback is not triggered. This lets you cross-connect widgets without creating endless loops.

Connecting GUI Inputs

The crucial thing is that GTK signals and attributes are isomorphic with Reactive Banana events and behaviors. So the following code gets you quite a long way:

   registerIOSignal :: (MonadIO m) =>
      object
      -> Signal object (m a)
      -> m (a, b)
      -> MomentIO (Event b)
   registerIOSignal obj sig act = do
      (event, runHandlers)
      liftIO $ obj `on` sig $ do
         (r, v) <- act
         liftIO $ runHandlers v
         return r
      return event

There are a few wrinkles that this has to cope with:

First, a few signal handlers expect the callback to return something other than "()". Hence the "a" type parameter above.

Second, the callback doesn't usually get any arguments, such as the current slider position. Its up to the callback itself to get whatever information it needs. Hence you still need to write some callback code.

Third, some signals work in monads other than just "IO". Usually these are of the form "ReaderT IO" (that is, IO plus some read-only context). The "m" type parameter allows for this.

So now we can get a Reactive Banana event for the slider like this:

   sliderEvent <- registerIOSignal mySlider valueChanged $ do
      v <- rangeGetValue mySlider
      return ((), v)

The two values in the "return" are the return value for the callback (which is just () in this case) and the value we want to send out in the Event.

Some signals do provide parameters directly to the callback, so you need a family of functions like this:

   registerIOSignal1 :: (MonadIO m) =>
      object
      -> Signal object (a -> m b)
      -> (a -> m (b, c))
      -> MomentIO (Event c)
   registerIOSignal2 :: (MonadIO m) =>
      object
      -> Signal object (a -> b -> m c)
      -> (a -> b -> m (c, d))
      -> MomentIO (Event d)

And so on up to registerIOSignal4, which is the longest one I have needed so far.

Connecting Outputs

Outputs are simpler than inputs. Reactive Banana provides a function for linking an event to an IO action:

 reactimate :: Event (IO ()) -> MomentIO ()

This takes an event carrying IO actions and executes those actions as they arrive. The "MomentIO" return value is the monad used for building up networks of events and behaviors: more of that in "Plumbing" below.

Events are functors, so the usual pattern for using reactimate looks like this:

   reportThis :: Event String -> MomentIO ()
   reportThis ev = do
      let ioEvent = fmap putStrLn ev
      reactimate ioEvent

The argument is an event carrying a string. This is converted into an event carrying IO actions using "fmap", and the result is then passed to reactimate. Obviously this can be reduced to a single line but I've split it out here to make things clearer.

So we can link an event to a GTK attribute like this:

   eventLink :: object -> Attr object a -> Event a -> MomentIO ()
   eventLink obj attr =
      reactimate . fmap (\v -> set obj [attr := v])

Whenever the argument event fires the attribute will be updated with the value carried by the event.

Behaviors can be linked in the same way. Reactive Banana provides the "changes" function to get an event whenever a behavior might have changed. However this doesn't quite work the way you would expect. The type is:

   changes :: Behavior a -> MomentIO (Event (Future a))

The "Future" type reflects the fact that a behavior only changes after the event processing has finished. This lets you write code that cross-links events and behaviors without creating endless loops, but it means you have to be careful when accessing the current value of a behavior. More about this in "Plumbing" below.

To cope with these "Future" values there is a special version of "reactimate" called "reactimate' " (note the tick mark). You use it like this:

   behaviorLink :: object -> Attr object a -> Behavior a -> MomentIO ()
   behaviorLink obj attr bhv = do
      fe <- changes bhv
      reactimate' $ fmap (fmap (\v -> set obj [attr := v])) fe

This will update the attribute whenever an event occurs which feeds in to the behavior. Note that this will still happen even if the new value is the same as the old; unlike GTK the Reactive Banana library doesn't cancel updates if the new and old values are the same.

Plumbing

The Basic Concepts

Reactive Banana events and behaviors are connected together in the MomentIO monad. This is an instance of MonadFix so you can use recursive do notation, letting you create feedback loops between behaviors and events. MomentIO is also an instance of MonadIO, so you can use liftIO to bring GTK widget actions into it.

To set up a dialog containing a bunch of GTK widgets you do the following things in the MomentIO monad:

  • Use liftIO on GTK functions to set up the widgets and arrange them in layout boxes in the same way you would if you were just using bare GTK.

  • Use registerIOSignal to get Reactive Banana events from the widgets.

  • Use the Reactive Banana combinators to create new events and behaviors reflecting the application logic you want.

  • Use eventLink and behaviorLink to update widget attributes.

 For instance you can have a pop-up dialog containing a bunch of input widgets with events attached to their values. Lets say these fields are arguments to the "FooData" constructor, and you also have a function "fooValid :: FooData -> Bool". You can then write your code like this:

   fooDialog :: FooData -> MomentIO (Widget, Event FooData)
   fooDialog (FooData v1 v2)= do

      -- Create GTK widgets w1, w2 and okButton.
      -- Put them all in a top-level "dialog" container.
      .... your GTK code here.

      -- Connect events ev1, ev2 to the values of w1 and w2.
      .... your calls to registerIOSignal here.
      okClick <- registerIOSignal okButton buttonActivate $ return ((), ())
      bhv1 <- stepper v1 ev1
      bhv2 <- stepper v2 ev2
      let
         fooB = FooData <$> bhv1 <*> bhv2
               -- Behavior is an Applicative, so fooB :: Behavior FooData
         validInput = fooValid <$> fooB
         result = const <$> fooB <@> okClick

      behaviorLink okButton widgetSensitive validInput
      return (dialog, result)

The last line but one links the "validInput" behavior to the OK button sensitivity. So if the input data is not valid then the OK button is greyed out and will not respond to clicks. You can use the same technique do other more informative things like highlighting the offending widget or displaying a helpful  message in another widget.

The "result =" line needs a bit of explanation. The "<@>" combinator in Reactive Banana works like the applicative "<*>" except that its second argument is an event rather than a behavior. The result is an event that combines the current value of the "fooB" behavior with the value from the "okClick" event. In this case the button click carries no information, so we use the function "const" to just take the current behavior value.

One tip: when writing pure functions that are going to be called using the "<@>" combinator its a good idea to put the argument that will come from the event last.

Keeping it Modular

I have found that these are good rules for designing applications in Reactive Banana:

  • Functions in the MomentIO monad should take events and behaviors as parameters, but only return events.

  • Avoid returning a behavior unless you are sure that this is the only function that needs to change it.

  • Keep the behavior definitions at the top of the call stack where they are used. If in doubt, defer the job of defining the behavior to your caller.

This lets you write independent modules that all have a say in updates to some shared value. The shared value should be represented as a Behavior, and updates to it as Events which either carry new values or (better) update functions. So you have a bunch of independent editor functions and a top level function which looks like this:

   editor1, editor2, editor3 ::
    Behavior FooData -> MomentIO (Event (FooData -> FooData))

   fooDataManager :: FooData -> MomentIO ()
   fooDataManager start = mdo    -- Recursive do notation.
      edit1 <- editor1 fooB
      edit2 <- editor2 fooB
      edit3 <- editor3 fooB
      fooB <- accumB start $ unions [edit1, edit2, edit3]
     -- accumB applies each event function to the accumulated behaviour value.