Skip to content

Instantly share code, notes, and snippets.

@Janiczek
Forked from cschneid/Counter.elm
Last active March 3, 2016 19:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Janiczek/056d40574548df9cfb86 to your computer and use it in GitHub Desktop.
Save Janiczek/056d40574548df9cfb86 to your computer and use it in GitHub Desktop.
import Signal exposing (Signal, Address)
import Html exposing (Html, div, button, text)
import Html.Events exposing (onClick)
-- There would normally be "import StartApp.Simple as StartApp exposing (start)
-- but for learning purposes we roll our own at the bottom.
-- Check it out after grasping this Counter example!
-- Our Counter will
-- 1. display a number
-- 2. let the user increment it
-- 3. let the user decrement it
main : Signal Html -- The entry point to the whole app. We need a Signal (think of it as of a stream) of Html
main =
start { model = model
, view = view
, update = update }
type alias Model = Int -- Our data is just a number.
model : Model -- Initial value
model = 0
view : Address Action -> Model -> Html -- Each HTML element has a list of Attributes and a list of children.
view address model =
div []
[ button [ onClick address Decrement ] [ text "-" ]
, div [] [ text (toString model) ]
, button [ onClick address Increment ] [ text "+" ]
]
type Action = Increment -- Our high-level descriptions of what can happen to the model.
| Decrement -- We could for example add a Reset action, Double action, etc...
update : Action -> Model -> Model -- What happens to the model with each action?
update action model = -- We could clean our update fn and refactor these
case action of -- to eg. `Increment -> updateIncrement model`
Increment -> model + 1 -- where `updateIncrement model = model + 1`.
Decrement -> model - 1 -- Equational reasoning FTW!
-----------------------------------------------------------
-- StartApp
-----------------------------------------------------------
type alias App model action = -- What do we want from the user.
{ model : model
, view : Address action -> model -> Html
, update : action -> model -> model
}
start : App Model Action -> Signal Html -- The goal is to give a Signal (stream) of Html to the browser.
start app =
let
actions : Signal.Mailbox (Maybe Action) -- we create a mailbox (has an .address where we can Signal.send, and .signal)
actions = -- there will be Actions flowing eventually,
Signal.mailbox Nothing -- but at first there is no value. (type Maybe a = Nothing | Just a)
address : Signal.Address Action -- we don't want the user
address = -- to have to wrap his Actions in Just
Signal.forwardTo actions.address Just -- so this is where we do that automatically for him
step : Maybe Action -> Model -> Model -- again, don't make the user
step action model = -- unwrap the Maybe Action in his `update` function
case action of -- he doesn't have to know about any of this!
Nothing -> model
Just action' -> app.update action' model
model : Signal Model -- finally, the Big Loop (TM)
model =
Signal.foldp -- this is basically a `reduce`
step -- function
app.model -- initial value
actions.signal -- where to take values from
in
Signal.map (app.view address) model -- Signal Model becomes Signal Html
-----------------------------------------------------------
-- End StartApp
-----------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment