-
Notifications
You must be signed in to change notification settings - Fork 0
/
Parallel.elm
164 lines (115 loc) · 4.04 KB
/
Parallel.elm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
module Parallel exposing (..)
import Html exposing (div, text, button, Html, img)
import Html.Attributes exposing (src, height)
import Html.Events exposing (onClick)
import Http
import Json.Decode as Decode
import Task
main : Program Never Model Msg
main =
Html.program
{ init = { flash = "starting", values = [], partialValues = [] } ! [ getValues ]
, view = view
, update = update
, subscriptions = \_ -> Sub.none
}
-- Model
type alias Model =
{ flash : String
, values : List String
, partialValues : List String
}
-- View
view : Model -> Html Msg
view model =
div []
[ div [] [ text model.flash ]
, button [ onClick Request ] [ text "add img" ]
, div [] (List.map (\v -> img [ src v, height 50 ] []) model.values)
]
-- Update
type Msg
= Request
| Success (List String)
| PartialSuccess (Model -> ( Model, Cmd Msg ))
| Error Http.Error
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
Request ->
{ model | flash = "requesting" } ! [ getValues ]
Success values ->
{ model | flash = "success", values = model.values ++ values } ! []
Error msg ->
{ model | flash = errorMapper msg } ! []
PartialSuccess updater ->
updater model
getValues : Cmd Msg
getValues =
parallelize parseHttpResults requestTasks
requestTasks : List (Task.Task Http.Error String)
requestTasks =
List.map Http.toTask requests
requests : List (Http.Request String)
requests =
List.map request [ "explosion", "rainbow", "ocean" ]
request : String -> Http.Request String
request searchTerm =
Http.get
("https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=" ++ searchTerm)
(Decode.at [ "data", "image_url" ] Decode.string)
errorMapper : Http.Error -> String
errorMapper error =
"Http Error: "
++ case error of
Http.BadUrl s ->
"you did not provide a valid URL" ++ s
Http.Timeout ->
"it took too long to get a response"
Http.NetworkError ->
"the user turned off their wifi, went in a cave, etc"
Http.BadStatus _ ->
"got a response back, but the status code indicates failure"
Http.BadPayload s _ ->
"got a response back with a nice status code, but the body of the response was something unexpected" ++ s
parseHttpResults : Result Http.Error (List String) -> Msg
parseHttpResults result =
case result of
Ok values ->
Success values
Err msg ->
Error msg
-- Parallelize
-- TODO make sure results in same order as corresponding tasks.
parallelize :
(Result a (List String) -> Msg)
-> List (Task.Task a String)
-> Cmd Msg
parallelize taskForker tasks =
Cmd.batch
(List.indexedMap
(\index task ->
Task.attempt
(\result ->
case result of
Ok value ->
PartialSuccess
(\model ->
if (allFinished tasks model.partialValues) then
( { model | partialValues = [] }, cmdSuccess taskForker (model.partialValues ++ [ value ]) )
else
( { model | partialValues = model.partialValues ++ [ value ] }, Cmd.none )
)
Err msg ->
taskForker (Result.Err msg)
)
task
)
tasks
)
allFinished : List a -> List b -> Bool
allFinished tasks partialValues =
List.length tasks == List.length partialValues + 1
cmdSuccess : (Result error a -> Msg) -> a -> Cmd Msg
cmdSuccess taskForker values =
Task.perform (\_ -> taskForker (Result.Ok values)) (Task.succeed values)