我如何获得Elm 0.17/0.18的当前时间?

z5h*_*z5h 14 functional-programming frp elm

我已经问过这个问题:
我如何获得Elm的当前时间?

并通过编写我自己的(现已弃用)start-app变体来回答:http:
//package.elm-lang.org/packages/z5h/time-app/1.0.1

当然,榆树建筑已经发生了变化,我旧的做事方式不再有效,因为没有信号或Time.timestamp.

所以....

假设我使用标准更新函数签名构建应用程序:
update : Msg -> Model -> (Model, Cmd Msg)

我想用更新的时间给我的模型加时间戳.一个不可接受的几乎解决方案是订阅Time.every.从概念上讲,这不是我想要的.这是随着时间更新模型,也是用消息单独更新模型.

我想要的是能够写一个带签名的更新函数:
updateWithTime : Msg -> Time -> Model -> (Model, Cmd Msg)


我开始尝试通过添加一些额外的消息来解决这个问题:
Msg = ... When | NewTime Time

并创建一个新命令:
timeCmd = perform (\x -> NewTime 0.0) NewTime Time.now

因此,在任何操作中,我都可以触发额外的命令来检索时间.但是这很快就会变得混乱和失控.

关于我如何清理它的任何想法?

rob*_*oby 9

无需在每个更新路径上执行时间提取的一个选项是将您Msg的另一个消息类型包装起来,以获取时间然后update随时间调用您的法线.这是http://elm-lang.org/examples/buttons的修改版本,它将在每次更新时更新模型的时间戳.

import Html exposing (div, button, text)
import Html.App exposing (program)
import Html.Events exposing (onClick)
import Task
import Time exposing (Time)


main =
  program { init = (Model 0 0, Cmd.none), view = view, update = update, subscriptions = (\_ -> Sub.none) }

type alias Model =
  { count: Int
  , updateTime : Time
  }

view model =
  Html.App.map GetTimeAndThen (modelView model)

type Msg
  = GetTimeAndThen ModelMsg
  | GotTime ModelMsg Time

update msg model =
  case msg of
    GetTimeAndThen wrappedMsg ->
      (model, Task.perform (\_ -> Debug.crash "") (GotTime wrappedMsg) Time.now)

    GotTime wrappedMsg time ->
      let
        (newModel, cmd) = modelUpdate wrappedMsg time model
      in
        (newModel, Cmd.map GetTimeAndThen cmd)

type ModelMsg = Increment | Decrement

modelUpdate msg time model =
  case msg of
    Increment ->
      ({model | count = model.count + 1, updateTime = time}, Cmd.none)

    Decrement ->
      ({model | count = model.count - 1, updateTime = time}, Cmd.none)

modelView model =
  div []
    [ button [ onClick  Decrement ] [ text "-" ]
    , div [] [ text (toString model.count) ]
    , button [ onClick  Increment ] [ text "+" ]
    , div [] [ text (toString model.updateTime) ]
    ]
Run Code Online (Sandbox Code Playgroud)


w.b*_*ian 8

我已经找到了我认为比接受的答案更优雅的解决方案.该GetTimeAndThen消息不是拥有两个单独的模型,而是拥有一个返回消息的处理程序.代码感觉更自然,更像榆树,可以更通用的方式使用:

module Main exposing (..)

import Html exposing (div, button, text)
import Html.App as App
import Html.Events exposing (onClick)
import Task
import Time exposing (Time)


main =
    App.program
        { init = ( Model 0 0, Cmd.none )
        , view = view
        , update = update
        , subscriptions = (\_ -> Sub.none)
        }


view model =
    div []
        [ button [ onClick decrement ] [ text "-" ]
        , div [] [ text (toString model) ]
        , button [ onClick increment ] [ text "+" ]
        ]


increment =
    GetTimeAndThen (\time -> Increment time)


decrement =
    GetTimeAndThen (\time -> Decrement time)


type Msg
    = Increment Time
    | Decrement Time
    | GetTimeAndThen (Time -> Msg)


type alias Model =
    { count : Int, updateTime : Time }


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GetTimeAndThen successHandler ->
            ( model, (Task.perform assertNeverHandler successHandler Time.now) )

        Increment time ->
            ( { model | count = model.count + 1, updateTime = time }, Cmd.none )

        Decrement time ->
            ( { model | count = model.count - 1, updateTime = time }, Cmd.none )


assertNeverHandler : a -> b
assertNeverHandler =
    (\_ -> Debug.crash "This should never happen")
Run Code Online (Sandbox Code Playgroud)

  • 这是一个有趣的想法,也是我从未考虑过的.我应该注意[目前在Elm中没有时间旅行的调试器](https://github.com/elm-lang/elm-reactor),尽管它最终会回来. (3认同)
  • 虽然我真的很喜欢这个答案,但我会取消选择它作为正确的答案.原因是,如果应用程序的模型和消息是可序列化的,则可以记录和回放应用程序的历史记录(对于时间旅行调试器很重要).函数不可序列化,因此在模型中包含函数或操作不能与时间调度器一起使用. (2认同)

rof*_*rol 7

elm-0.18完整示例https://runelm.io/c/72i

import Time exposing (Time)
import Html exposing (..)
import Html.Events exposing (onClick)
import Task

type Msg
    = GetTime
    | NewTime Time

type alias Model =
    { currentTime : Maybe Time
    }

view : Model -> Html Msg
view model =
    let
        currentTime =
            case model.currentTime of
                Nothing ->
                    text ""

                Just theTime ->
                    text <| toString theTime
    in
        div []
            [ button [ onClick GetTime ] [ text "get time" ]
            , currentTime
            ]

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GetTime ->
            model ! [ Task.perform NewTime Time.now ]

        NewTime time ->
            { model | currentTime = Just time } ! []

main : Program Never Model Msg
main =
    program
        { init = init
        , update = update
        , view = view
        , subscriptions = always Sub.none
        }

init : ( Model, Cmd Msg )
init =
    { currentTime = Nothing } ! []
Run Code Online (Sandbox Code Playgroud)