Transcript Elm 2

Elm
Signals and Suggestions
Working online


In general, I found working online at http://elm-lang.org/try to be the best
way to program Elm
 Instant feedback, so you can try one change at a time and see if it worked
 No good way to save your work; I did an occasional copy-all and paste
into Sublime Text
 The images used in the examples are on the server, not locally, so you
can’t readily use them in your own program
I installed Elm and used the elm repl to test single expressions and very
small bits of code
 The REPL is especially useful for entering expressions to find out their
type

> Signal.map
<function: map> : (a -> b) -> Signal.Signal a -> Signal.Signal b
2
Program structure



Elm programs have a structure very similar to MVC (Model-View-Controller)
The structure is Model - Update - View, or sometimes Model - Update - View Signals
In Elm
 The Model is typically just data, describing the current state of the program;
typically this is in the form of a record named model
 The Update is a set of pure functions; typically there is a function named
update with a signature similar to Input -> Model -> Model
 The View is a set of functions whose purpose is to display the current state;
typically there is a function named view with a signature something like
Input -> Model -> Element
 The Signals part includes a function named main; it collects signals together
and bundles them up, sends them to update to get a new program state, and
sends the result to view
3
Mouse signals

import Mouse exposing (..)
 position : Signal ( Int, Int )
 x : Signal Int
 y : Signal Int
 isDown : Signal Bool
 clicks : Signal ()
4
Keyboard signals


import Keyboard exposing (..)
 Mouse.position : Signal (Int, Int)
 arrows : Signal { x : Int, y : Int }
 wasd : Signal { x : Int, y : Int }
 enter, space, ctrl, shift, alt, meta are all Signal
Bool
type alias KeyCode = Int
 isDown : KeyCode -> Signal Bool
 keysDown : Signal (Set KeyCode)
 presses : Signal KeyCode -- most recent key
pressed
5
Time signals

import Time exposing (..)
 fps : number -> Signal Time
 fps (frames per second) will produce a signal the given
number of times every second
 fpsWhen : number -> Signal Bool -> Signal Time
 Same as the fps function, but you can turn it on and off
 every : Time -> Signal Time
 Takes a time interval t and produces a signal updated every
t
 delay : Time -> Signal a -> Signal a
 Delays a time signal
 There a few additional functions
6
Window signals

import Window exposing (..)
 dimensions : Signal ( Int, Int )
 width : Signal Int
 height : Signal Int

When you embed Elm in a <div> it gives the
dimensions of the container, not the whole window
7
Monads

Signal is a monad type
 Signals, by definition, vary over time
 Clearly, this is inappropriate for a pure functional language
 Monads “isolate” impure operations

The main function in the Signals part of an Elm program:
1. Collects signals together and bundles them up
2. Extracts the data from the signals and sends them to the
pure function update to get a new program state
3. Sends the new program state to view
8
Bind


Remember “bind” (>>=) in Haskell?
 bind takes a value out of a monad, applies a function to it, and
puts the result back into a monad:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Elm has something similar but not identical
 Signal.map : (a -> b) -> Signal a -> Signal b
 This allows us to take a Signal a, use it to call a pure function
(a -> b), and get the result as a Signal b
 The arguments are reversed from those of >>= but in the same
order as those of List.map
 List.map : (a -> b) -> List a -> List b
 <~ is an alias for Signal.map
9
Signal.mapn


Signal.map applies a pure function to the value inside a Signal, producing another
Signal
 Signal.map : (a -> b) -> Signal a -> Signal b
However, you often have pure functions that take more than a single argument
 map2 : (a -> b -> result) -> Signal a -> Signal b -> Signal
result
 The result type is, of course, up to the supplied function, but is often a tuple
 map3 : (a -> b -> c -> result) -> Signal a -> Signal b ->
Signal c -> Signal result
 map4 :
(a -> b -> c -> d -> result)
-> Signal a
-> Signal b
-> Signal c
-> Signal d
-> Signal result
 map5 -- the obvious type is omitted for reasons of space
10
Warning! lift




Elm is a new and rapidly changing language
If you find examples using the functions lift, lift2,
lift3, etc., these functions no longer exist
They have been replaced by map, map2, map3, etc.
The old functions have the same signature as the new,
and as far as I know, is just a name change
11
Sampling



import Signal exposing (..)
sampleOn : Signal a -> Signal b -> Signal b
 Sample from the second input every time an event occurs on
the first input. For example, (sampleOn clicks (every
second)) will give the approximate time of the latest click
 The value of the first signal (Signal a) is discarded
I believe that the purpose of sampleOn is to restrict the number of
events that must be handled by the update and view parts of the
program
 Mouse.position can probably produce hundreds of events a
second
12
foldp


foldp folds signals “over time”
From the documentation:
foldp : (a -> state -> state) -> state ->
Signal a -> Signal state
Create a past-dependent signal. Each update from the
incoming signals will be used to step the state forward.
The outgoing signal represents the current state.
13
Mario example I

main : Signal Element
main =
Signal.map2 view Window.dimensions
(Signal.foldp update mario input)

view : (Int, Int) -> Model -> Element

update : (Float, Keys) -> Model -> Model
14
Mario example II

main : Signal Element
main =
Signal.map2 view Window.dimensions
(Signal.foldp update mario input)

input : Signal (Float, Keys)
input =
let
delta = Signal.map (\t -> t/20) (fps 30)
in
Signal.sampleOn delta (Signal.map2 (,)
delta Keyboard.arrows)
15
Modified Mario I


I modified the Mario example to also accept mouse position
signals
main : Signal Element
main =
Signal.map3 view Window.dimension
Mouse.position (Signal.foldp update
mario input)

view : (Int, Int) -> (Int, Int) -> Model ->
Element

update : (Float, Keys) -> Model -> Model
16
Modified Mario II

main : Signal Element
main =
Signal.map3 view Window.dimension
Mouse.position (Signal.foldp update
mario input)

input : Signal (Float, Keys, Location)
input =
let
delta = Signal.map (\t -> t/20) (fps 30)
in
Signal.sampleOn delta (Signal.map3 (,,) delta
Keyboard.arrows Mouse.position)
17
Modified Mario III


type alias Model =
{ x : Float
, y : Float
, vx : Float
, vy : Float
, dir : Direction
, mouse : (Int, Int)
}
update : (Float, Keys, Location) -> Model -> Model
update (dt, keys, position) mario =
mario
|> gravity dt
|> jump keys
|> walk keys
|> physics dt
|> attract position -- defined as
type alias Location = (Int, Int)
18
Questions

main : Signal Element
main =
Signal.map3 view Window.dimension
Mouse.position (Signal.foldp update
mario input)
input : Signal (Float, Keys, Location)
input =
let
delta = Signal.map (\t -> t/20) (fps 30)
in
Signal.sampleOn delta (Signal.map3 (,,) delta
Keyboard.arrows Mouse.position)


Why isn’t Window.dimension handled in input?
Why do I need to mention Mouse.position twice?
19
Collage example


A Collage is used to display things on the screen
view : (Int, Int) -> (Int, Int) -> Model -> Element
view (w',h') mario =
let
-- many definitions omitted: w, h, marioImage, etc.
in
collage w' h'
[ rect w h
|> filled (rgb 174 238 238)
, rect w 50
|> filled (rgb 74 167 43)
|> move (0, 24 - h/2)
, marioImage
|> toForm
|> move position
]
20
The End
21