Apanatshka's answer (and others) made sense, but as a beginner to Elm I had trouble applying the explanation to actual code. After some fuddling around, here is a minimal amount of code needed to render an auto-updating date (using Elm v0.16.0):
import Signal
import Html exposing (Html, text)
import Time exposing (Time, every)
import Date exposing (Date, Month, fromTime, year, month, day, hour, minute, second)
-- not used by foldp (https://stackoverflow.com/a/34095298/480608)
startTime = 0
type Action = Update Date
type alias Model = Date
showDate : Date -> String
showDate date = toString (month date) ++ " " ++
toString (day date) ++ ", " ++
toString (year date) ++ " " ++
toString (hour date) ++ ":" ++
toString (minute date) ++ ":" ++
toString (second date)
update : Action -> Model -> Model
update (Update date) _ = date
model : Signal Model
model =
Signal.foldp update (fromTime startTime) clock
timeToAction : Time -> Action
timeToAction time = Update <| fromTime time
clock : Signal Action
clock =
Signal.map timeToAction <| every Time.second
main : Signal Html
main =
Signal.map view model
view : Model -> Html
view model =
text <| showDate model
Here's a slightly more complex example that merges the clock into other signals. No idea how well this conforms to elm best practices, but it works, and it may serve as a helpful learning tool as it did for me.
import Signal
import Html exposing (..)
import Html.Events exposing (..)
import Keyboard
import Char
import Time exposing (Time)
import Date exposing (Date, Month, fromTime, year, month, day, hour, minute, second)
startTime = 0
type Action =
NoOp
| Increment
| Decrement
| Update Time
type alias Model = {
count: Int,
time: Time
}
showDate : Date -> String
showDate date = toString (month date) ++ " " ++
toString (day date) ++ ", " ++
toString (year date) ++ " " ++
toString (hour date) ++ ":" ++
toString (minute date) ++ ":" ++
toString (second date)
actions : Signal.Mailbox Action
actions =
Signal.mailbox NoOp
update : Action -> Model -> Model
update action model =
case action of
NoOp -> model
Increment -> { model | count = model.count + 1 }
Decrement -> { model | count = model.count - 1 }
Update time -> { model | time = time }
model : Signal Model
model =
Signal.foldp update { count = 0, time = startTime } (Signal.mergeMany [
actions.signal,
keyPressesToAction,
clock
])
keyPressesToAction : Signal Action
keyPressesToAction =
let
keyCodeToAction keyCode =
case Char.fromCode keyCode of
'=' -> Increment
'-' -> Decrement
_ -> NoOp
in
Signal.map keyCodeToAction Keyboard.presses
timeToAction : Time -> Action
timeToAction time = Update time
clock : Signal Action
clock = Signal.map timeToAction (Time.every Time.second)
main : Signal Html
main =
Signal.map (view actions.address) model
view : Signal.Address Action -> Model -> Html
view address model =
div [] [
text <| showDate <| fromTime model.time,
div []
[ button [ onClick address Decrement ] [ text "-" ]
, text <| toString model.count
, button [ onClick address Increment ] [ text "+" ]
]
]