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
因此,在任何操作中,我都可以触发额外的命令来检索时间.但是这很快就会变得混乱和失控.
关于我如何清理它的任何想法?
无需在每个更新路径上执行时间提取的一个选项是将您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)
我已经找到了我认为比接受的答案更优雅的解决方案.该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)
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)
| 归档时间: |
|
| 查看次数: |
2994 次 |
| 最近记录: |