This repository has been archived by the owner. It is now read-only.
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
214 lines (163 sloc) 6.54 KB
module Effects
( Effects, none, task, tick
, map, batch
, Never
, toTask
{-| This module provides all the tools necessary to create modular components
that manage their own effects. **It is very important that you go through
[this tutorial](** It
describes a pattern that is crucial for any of these functions to make sense.
# Basic Effects
@docs Effects, none, task, tick
# Combining Effects
@docs map, batch
# Helpers
There are some common patterns that will show up in folks code a lot, so there
are some helper functions you may want to define in your own code. For example,
the `noFx` function makes it easier to return a model without any effects.
import Effects exposing (Effects)
noFx : model -> (model, Effects a)
noFx model =
(model, Effects.none)
This way you don't have to add the tuple in, just say something like
`(noFx <| ...)` and get the same result.
If folks find this helpful, we will add it to this library. Let us know your
experience in an issue.
# Running Effects
@docs toTask, Never
import Native.Effects
import Task
import Time exposing (Time)
{-| Represents some kind of effect. Right now this library supports tasks for
arbitrary effects and clock ticks for animations.
type Effects a
= Task (Task.Task Never a)
| Tick (Time -> a)
| None
| Batch (List (Effects a))
{-| A type that is "uninhabited". There are no values of type `Never`, so if
something has this type, it is a guarantee that it can never happen. It is
useful for demanding that a `Task` can never fail.
type Never = Never Never
{-| The simplest effect of them all: don’t do anything! This is useful when
some branches of your update function request effects and others do not.
Example 5 in [elm-architecture-tutorial](
has a nice example of this with further explanation in the tutorial itself.
none : Effects a
none =
{-| Turn a `Task` into an `Effects` that results in an `a` value.
Normally a `Task` has a error type and a success type. In this case the error
type is `Never` meaning that you must provide a task that never fails. Lots of
tasks can fail (like HTTP requests), so you will want to use `Task.toMaybe`
and `Task.toResult` to move potential errors into the success type so they can
be handled explicitly.
Example 5 in [elm-architecture-tutorial](
has a nice example of this with further explanation in the tutorial itself.
task : Task.Task Never a -> Effects a
task =
{-| Request a clock tick for animations. This function takes a function to turn
the current time into an `a` value that can be handled by the relevant component.
Example 8 in [elm-architecture-tutorial](
has a nice example of this with further explanation in the tutorial itself.
tick : (Time -> a) -> Effects a
tick =
{-| Create a batch of effects. The following example requests two tasks: one
for the user’s picture and one for their age. You could put a bunch more stuff
in that batch if you wanted!
init : String -> (Model, Effects Action)
init userID =
( { id = userID
, picture = Nothing
, age = Nothing
, batch [ getPicture userID, getAge userID ]
-- getPicture : String -> Effects Action
-- getAge : String -> Effects Action
Example 6 in [elm-architecture-tutorial](
has a nice example of this with further explanation in the tutorial itself.
batch : List (Effects a) -> Effects a
batch =
{-| Transform the return type of a bunch of `Effects`. This is primarily useful
for adding tags to route `Actions` to the right place in The Elm Architecture.
Example 6 in [elm-architecture-tutorial](
has a nice example of this with further explanation in the tutorial itself.
map : (a -> b) -> Effects a -> Effects b
map func effect =
case effect of
Task task ->
Task ( func task)
Tick tagger ->
Tick (tagger >> func)
None ->
Batch effectList ->
Batch ( (map func) effectList)
{-| Convert an `Effects` into a task that cannot fail. When run, the resulting
task will send a bunch of message lists to the given `Address`. As an invariant,
no empty list will ever be sent. Non-singleton lists will only ever be sent for
effects created with [`tick`](#tick). Those may be batched even over different
calls to `toTask` with the same `Address`. In such lists, the order of elements
is not significant.
Generally speaking, you should not need this function, particularly if you are
using [start-app](
It is mainly useful at the very root of your program where you actually need to
give all the effects to a port. So in the common case you should use this
function 0 times per project, and if you are doing very special things for
expert reasons, you should probably have either 0 or 1 uses of this per
toTask : Signal.Address (List a) -> Effects a -> Task.Task Never ()
toTask address effect =
(combinedTask, tickMessages) =
toTaskHelp address effect (Task.succeed (), [])
if List.isEmpty tickMessages then
combinedTask `Task.andThen` always (requestTickSending address tickMessages)
: Signal.Address (List a)
-> Effects a
-> (Task.Task Never (), List (Time -> a))
-> (Task.Task Never (), List (Time -> a))
toTaskHelp address effect ((combinedTask, tickMessages) as intermediateResult) =
case effect of
Task task ->
reporter =
task `Task.andThen` (\answer -> Signal.send address [answer])
( combinedTask `Task.andThen` always (ignore (Task.spawn reporter))
, tickMessages
Tick toMsg ->
( combinedTask
, toMsg :: tickMessages
None ->
Batch effectList ->
List.foldl (toTaskHelp address) intermediateResult effectList
requestTickSending : Signal.Address (List a) -> List (Time -> a) -> Task.Task Never ()
requestTickSending =
ignore : Task.Task x a -> Task.Task x ()
ignore task = (always ()) task