evancz/Elm — pull request #29 by joeyadams (2012-09-29 03:31:10+00:00)
Title: Add variant of foldp whose initial value comes from the source signal

This adds a variant of `foldp` that can be used when you need some input to produce an initial value:

foldp1 :: (a -> b -> b) -> (a -> b) -> Signal a -> Signal b

See the commit message for documentation.

Motivation: now we can run `Signal` data through a [Mealy machine][1]:

import Signal.Mouse (clicks, x)

data Auto a b = Auto (a -> (b, Auto a b))

-- foldAuto :: Auto a b -> Signal a -> Signal b
foldAuto (Auto m0) input =
lift fst $ foldp1 (\a (b, Auto m) -> m a) m0 input

-- summer :: Auto Int Int
summer =
let go s = Auto (\n -> let s' = s+n in (s', go s'))
in go 0

main = lift asText $ foldAuto summer $ sampleOn clicks $ constant 5

The first thing this program prints is `5`, which can only happen if the `summer` is fed an input before producing its output.

We can't do this with `foldp` alone. This might not seem like an issue in practice, but it is if we want to write step functions using arrow composition.

### The Auto arrow

`Auto` is an arrow, allowing us to reap some of the benefits of arrowized FRP in Elm. Consider a function for creating a draggable circle:

dragCircle :: Int -- ^ Radius
-> (Int, Int) -- ^ Initial position
-> Signal (Shape, (Int, Int))

This interface cannot be used to create circles dynamically, since that would involve changing the signal graph. A more flexible version of `dragCircle` might look like:

dragCircleAuto :: Int -> (Int, Int)
-> Auto ((Int, Int), Bool) (Shape, (Int, Int))
dragCircleAuto r c = Auto $ \(mousePos, mouseDown) ->
...

dragCircleInput :: Signal ((Int, Int), Bool)
dragCircleInput = lift2 (,) position isDown

dragCircle r c = foldAuto (dragCircleAuto r c) dragCircleInput

`dragCircleAuto` is a pure function, meaning it can be incorporated into a larger step function without the limitations of `Signal`.

[1]: http://hackage.haskell.org/packages/archive/machines/latest/doc/html/Data-Machine-Mealy.html