Functional User Interfaces – Composability



Functional User Interfaces – Composability

0 2


funlx-meetup-2

My talk “Functional User Interfaces” at the Fun(Lx) meetup http://www.meetup.com/Fun-Lx/events/182710042/

On Github stanch / funlx-meetup-2

Functional User Interfaces

Nick @stanchmehttp://github.com/stanch

(please change slides with <space>)

Functional, huh?

Composability

Abstraction

User Interfaces

In a nutshell

  • Displaying stuff
  • Reacting to user input

The Awkward Layouts

What we need

  • Reusable
  • Composable
  • Flexible

Android XML

  • Awkward modularity

Javascript {{{}}}-s

  • String-based? Duh...

The Composable Layouts

ScalaTags *

  • Just Scala code
  • Use values and modules

Demo

Hiccup *

same idea in Clojure...

(html [:span {:class "foo"} "bar"])

Dommy *

and again...

(node
  [:div#id.class1
    (for [r (range 2)]
      [:span.text (str "word" r)])])

Teacup *

and in CoffeeScript...

output = render ->
  ul ->
    li 'Bergamot'
    li 'Chamomile'

TheFlyingSpaghettiCodeMonster

Wikipedia on Spaghetti

UI is the new black

Adobe on UI *

  • 1/3 code is event handling
  • 1/2 bugs are in that code

Dataflow programming

Establishing connections

Remember MS Excel?

Signals

  • Mouse is a signal
  • Textbox is a slot
  • We need the cable!

Elm *

  • Signal-based language
  • Compiles to HTML+CSS+JS

Demo

A complete example

Event Streams

  • Keypress is an event
  • Transform it
  • Connect to a textbox

bacon.js

  • JavaScript library
  • Turns DOM events into transformable streams

Demo

Observables

same idea

  • Reactive Extensions *
  • RxJava *

Meanwhile, in our phones

Macroid *

Experimental modular functional UI language for Android, written in Scala.

Bricks

w[Button]

Bricks

l[LinearLayout](
  w[Button],
  w[TextView]
)

Bricks

val brick1 = w[Button]
val brick2 = w[TextView]

l[LinearLayout](
  brick1, brick2
)

Tweaks

w[TextView] <~ text("Hello")

Tweaks

def largeText(str: String) =
  text(str) +
  TextSize.large +
  padding(left = 8 dp)

myTextView <~ largeText("Hello")

A complete layout

var greeting = slot[TextView]

l[LinearLayout](
  w[Button] <~
    text("Greet me!") <~
    On.click {
      greeting <~ show
    },

  w[TextView] <~
    text("Hello there") <~
    wire(greeting) <~ hide 
)

Snails

myTextView <~~ fadeIn(400)

Snails

myTextView <~~
  fadeIn(400) <~
  text("Faded!")

Snails

val blink =
  fadeIn(400) ++
  delay(2000) ++
  fadeOut(400)

myTextView <~~ blink

UI actions

val action =
  myTextView <~ text("Foo") <~ show

UI actions

val action1 =
  myTextView <~ text("Foo") <~ show

val action2 =
  myProgressBar <~ hide

runUi(action1 ~ action2)

UI actions

runUi {
  (myProgressBar <~~ fadeOut(400)) ~~
  (myTextView <~~ blink) ~~
  (myOtherTextView <~ text("’SUP?"))
}

Tweaks & Signals

// create a reactive variable
val caption = rx.Var("Olá")

// set text to “Olá”
myTextView <~ caption.map(text)

// text automatically updates to “Adeus”
caption.update("Adeus")

Advanced Ideas

Drawing a figure

  • Wait till mouse is down
  • Draw while it moves
  • Finish once mouse is up

Event Stream Workflows *

Reactor.loop { self ⇒
  // step 1
  val path = new Path((self await mouseDown).position)
  // step 2
  self.loopUntil(mouseUp) {
    val m = self awaitNext mouseMove
    path.lineTo(m.position)
    draw(path)
  }
  // step 3
  path.close()
  draw(path)
}

Demo