Created
September 9, 2016 21:23
-
-
Save markhamburg/b4613175fd65f6d25a58e3f9c0044a09 to your computer and use it in GitHub Desktop.
Another version of the counter with stack example for private state, this time with a utility to encapsulate the repeated update logic.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Html exposing (..) | |
import Html.Attributes exposing (..) | |
import Html.App | |
import Html.Events exposing (..) | |
type CounterMsg | |
= Decrement | |
| Increment | |
| Push | |
| Pop | |
type CounterPrivate = | |
Private (List Int) | |
-- Initialize the private data for a counter | |
initCounterPrivate : Int -> CounterPrivate | |
initCounterPrivate value = | |
Private [] | |
-- Update the private data for a counter given a change in | |
-- the public value | |
updateCounterPrivate : Int -> CounterPrivate -> CounterPrivate | |
updateCounterPrivate value old = | |
old | |
-- Generate a view for a counter with value stack | |
viewCounter : Int -> CounterPrivate -> Html CounterMsg | |
viewCounter value (Private stack) = | |
div [] | |
[ button [ onClick Decrement ] [ text "-" ] | |
, div [] [ text (toString value) ] | |
, button [ onClick Increment ] [ text "+" ] | |
, button [ onClick Push ] [ text "Push" ] | |
, button [ onClick Pop, disabled (stack == []) ] [ text "Pop" ] | |
] | |
-- Update for a counter with stack | |
updateCounter : CounterMsg -> Int -> CounterPrivate -> (Int, CounterPrivate) | |
updateCounter msg value ((Private stack) as private) = | |
case msg of | |
Decrement -> | |
(value - 1, private) | |
Increment -> | |
(value + 1, private) | |
Push -> | |
(value, Private <| value :: stack) | |
Pop -> | |
case stack of | |
[] -> (value, private) | |
x :: rest -> (x, Private rest) | |
-- Our model will have two view with private stacks working with | |
-- the same counter | |
type alias Model = | |
{ value : Int | |
, privateA : CounterPrivate | |
, privateB : CounterPrivate | |
} | |
type Msg | |
= ToA CounterMsg | |
| ToB CounterMsg | |
init : Int -> Model | |
init value = | |
{ value = value | |
, privateA = initCounterPrivate value | |
, privateB = initCounterPrivate value | |
} | |
view : Model -> Html Msg | |
view model = | |
div [] | |
[ Html.App.map ToA <| viewCounter model.value model.privateA | |
, Html.App.map ToB <| viewCounter model.value model.privateB | |
] | |
update : Msg -> Model -> Model | |
update msg model = | |
case msg of | |
ToA cmsg -> | |
updatePublicPrivate | |
(.value, setValue) | |
(.privateA, (\private model -> { model | privateA = private })) | |
updateCounter | |
cmsg | |
model | |
ToB cmsg -> | |
updatePublicPrivate | |
(.value, setValue) | |
(.privateB, (\private model -> { model | privateB = private })) | |
updateCounter | |
cmsg | |
model | |
type alias GetterSetter container value = | |
((container -> value), (value -> container -> container)) | |
updatePublicPrivate : | |
GetterSetter model public | |
-> GetterSetter model private | |
-> (msg -> public -> private -> (public, private)) | |
-> msg | |
-> model | |
-> model | |
updatePublicPrivate | |
(getPublic, setPublic) (getPrivate, setPrivate) update msg model = | |
let | |
(newPublic, newPrivate) = | |
update msg (getPublic model) (getPrivate model) | |
in | |
model |> setPublic newPublic |> setPrivate newPrivate | |
-- When we update the shared counter value, we provide an opportunity | |
-- for the private states to update as well. | |
setValue : Int -> Model -> Model | |
setValue newValue model = | |
if newValue == model.value then | |
model | |
else | |
{ model | |
| value = newValue | |
, privateA = updateCounterPrivate newValue model.privateA | |
, privateB = updateCounterPrivate newValue model.privateB | |
} | |
-- Wire it up and run it | |
main = | |
Html.App.beginnerProgram { model = init 0, view = view, update = update } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment