jfmengels / elm-review-simplify / Simplify

Reports when an expression can be simplified.

🔧 Running with --fix will automatically remove all the reported errors.

config =
    [ Simplify.rule Simplify.defaults
    ]

rule : Configuration -> Review.Rule.Rule

Rule to simplify Elm code.


type Configuration

Configuration for this rule. Create a new one with defaults and use ignoreCaseOfForTypes and expectNaN to alter it.

defaults : Configuration

Default configuration for this rule.

The rule aims tries to improve the code through simplifications that don't impact the behavior. An exception to this are when the presence of NaN values

Use expectNaN if you want to opt out of changes that can impact the behaviour of your code if you expect to work with NaN values.

Use ignoreCaseOfForTypes if you want to prevent simplifying case expressions that work on custom types defined in dependencies.

config =
    [ Simplify.rule Simplify.defaults
    ]

-- or
config =
    [ Simplify.defaults
        |> Simplify.expectNaN
        |> Simplify.ignoreCaseOfForTypes [ "Module.Name.Type" ]
        |> Simplify.rule
    ]

expectNaN : Configuration -> Configuration

Usually, elm-review-simplify will only suggest simplifications that are safe to apply without risk of changing the original behavior. However, when encountering NaN values, some simplifications can actually impact behavior.

For instance, the following expression will evaluate to True:

x == x
--> True

However, if x is NaN or a value containing NaN then the expression will evaluate to False:

-- given x = NaN
x == x
--> False

-- given x = { a = ( NaN, 0 ) }
x == x
--> False

Given the potential presence of NaN, some simplifications become unsafe to apply:

This special value is hard to recreate in Elm code both intentionally and unintentionally, and it's therefore unlikely to be found in your application, which is why the rule applies these simplifications by defaults.

If you somehow expect to create and encounter NaN values in your codebase, then you can use this function to disable these simplifications altogether.

config =
    [ Simplify.defaults
        |> Simplify.expectNaN
        |> Simplify.rule
    ]

ignoreCaseOfForTypes : List String -> Configuration -> Configuration

Ignore some reports about types from dependencies used in case expressions.

This rule simplifies the following construct:

module Module.Name exposing (..)

case value of
    Just _ -> x
    Nothing -> x
--> x

(Since v2.0.19) it will not try to simplify the case expression when some of the patterns references custom types constructors defined in the project. It will only do so for custom types that are defined in dependencies (including elm/core).

If you do happen to want to disable this simplification for a type Module.Name.Type, you can configure the rule like this:

config =
    [ Simplify.defaults
        |> Simplify.ignoreCaseOfForTypes [ "Module.Name.Type" ]
        |> Simplify.rule
    ]

I personally don't recommend to use this function too much, because this could be a sign of premature abstraction, and because I think that often You Aren't Gonna Need this code.

Please let me know by opening an issue if you do use this function, I am very curious to know;

Try it out

You can try this rule out by running the following command:

elm-review --template jfmengels/elm-review-simplify/example --rules Simplify

Simplifications

Below is the list of all kinds of simplifications this rule applies.

Booleans

x || True
--> True

x || False
--> x

x && True
--> x

x && False
--> False

not True
--> False

not (not x)
--> x

-- for `<`, `>`, `<=`, `>=`, `==` and `/=`
not (a < b)
--> a >= b

Comparisons

x == True
--> x

x /= False
--> x

not x == not y
--> x == y

anything == anything
--> True

anything /= anything
--> False

{ r | a = 1 } == { r | a = 2 }
--> False

If expressions

if True then x else y
--> x

if False then x else y
--> y

if condition then x else x
--> x

if condition then True else False
--> condition

if condition then False else True
--> not condition

a =
    if condition then
        if not condition then
            1
        else
            2
    else
        3
--> if condition then 2 else 3

Case expressions

case condition of
    True -> x
    False -> y
--> if condition then x else y

case condition of
    False -> y
    True -> x
--> if not condition then x else y

-- only when no variables are introduced in the pattern
-- and no custom types defined in the project are referenced
case value of
    Just _ -> x
    Nothing -> x
--> x

-- same with any variant, list or tuple containing either
case Just value of
    Nothing -> a
    Just (Ok b) -> c
    Just (Err d) -> e
--> case value of
-->     Ok b -> c
-->     Err d -> e

Destructuring using case expressions

case value of
    ( x, y ) ->
        x + y

-->
let
    ( x, y ) =
        value
in
x + y

Let expressions

let
    a =
        1
in
let
    b =
        1
in
a + b

-->
let
    a =
        1

    b =
        1
in
a + b

Record updates

{ a | b = a.b }
--> a

{ a | b = a.b, c = 1 }
--> { a | c = 1 }

Field access

{ a = b }.a
--> b

{ a | b = c }.b
--> c

{ a | b = c }.d
--> a.d

(let a = b in c).d
--> let a = b in c.d

(Record first second).first
--> first

Basics functions

identity x
--> x

f >> identity
--> f

always x y
--> x

f >> always x
--> always x

toFloat 1
--> 1

round 1
--> 1

ceiling 1
--> 1

floor 1
--> 1

truncate 1
--> 1

round (toFloat n) -- same for ceiling, floor and truncate
--> n

Lambdas

(\_ -> x) data
--> x

(\() y -> x) ()
--> (\y -> x)

(\_ y -> x) data
--> (\y -> x)

Operators

(++) a b
--> a ++ b

a |> f >> g
--> a |> f |> g

Numbers

n + 0
--> n

n - 0
--> n

0 - n
--> -n

n * 1
--> n

0 // n
--> 0

n // 0
--> 0

n // 1
--> n

n / 1
--> n

0 / n
--> 0

-(-n)
--> n

negate (negate n)
--> n

n - n
--> 0

Tuples

Tuple.pair a b
--> ( a, b )

Tuple.first ( a, b )
--> a

Tuple.first (Tuple.mapSecond changeFirst tuple)
--> Tuple.first tuple

Tuple.first (Tuple.mapBoth changeFirst changeSecond tuple)
--> Tuple.first (Tuple.mapFirst changeFirst tuple)

Tuple.second ( a, b )
--> b

Tuple.second (Tuple.mapFirst changeSecond tuple)
--> Tuple.second tuple

Tuple.second (Tuple.mapBoth changeFirst changeSecond tuple)
--> Tuple.second (Tuple.mapSecond changeSecond tuple)

Strings

"a" ++ ""
--> "a"

String.fromList []
--> ""

String.fromList [ a ]
--> String.fromChar a

String.fromList (String.toList str)
--> str

String.toList (String.fromList list)
--> list

String.isEmpty ""
--> True

String.isEmpty "a"
--> False

String.concat []
--> ""

String.concat [ string ]
--> string

String.concat [ hello, "", world ]
--> String.concat [ hello, world ]

String.concat [ "a", String.concat [ b, c ], d ]
--> String.concat [ "a", b, c, d ]

String.concat (List.repeat n str)
--> String.repeat n str

String.concat (List.intersperse str strings)
--> String.join str strings

String.append "" str
--> str

String.append (String.fromList [ a, b ]) (String.fromList [ c, d ])
--> String.fromList [ a, b, c, d ]

String.join str []
--> ""

String.join "" list
--> String.concat list

String.length "abc"
--> 3

String.repeat n ""
--> ""

String.repeat 0 str
--> ""

String.repeat 1 str
--> str

String.replace x y ""
--> ""

String.replace x x z
--> z

String.replace "x" "y" "z"
--> "z" -- only when resulting string is unchanged

String.words ""
--> [ "" ]

String.lines ""
--> [ "" ]

String.reverse ""
--> ""

String.reverse (String.fromChar a)
--> String.fromChar a

String.reverse (String.reverse str)
--> str

String.slice n n str
--> ""

String.slice n 0 str
--> ""

String.slice a z ""
--> ""

String.left 0 str
--> ""

String.left -1 str
--> ""

String.left n ""
--> ""

String.right 0 str
--> ""

String.right -1 str
--> ""

String.right n ""
--> ""

String.slice 2 1 str
--> ""

String.slice -1 -2 str
--> ""

-- The following simplifications for String.foldl also work for String.foldr
String.foldl f initial ""
--> initial

String.foldl (\_ soFar -> soFar) initial string
--> initial

Maybes

Maybe.map identity x
--> x

Maybe.map f Nothing
--> Nothing

Maybe.map f (Just x)
--> Just (f x)

-- the following simplifications for map2 work for all Maybe.mapN
Maybe.map2 f firstMaybe Nothing
--> Nothing

Maybe.map2 f (Just a) (Just b)
--> Just (f a b)

Maybe.andThen f Nothing
--> Nothing

Maybe.andThen (always Nothing) x
--> Nothing

Maybe.andThen (\a -> Just b) x
--> Maybe.map (\a -> b) x

Maybe.andThen (\a -> if condition a then Just b else Just c) x
--> Maybe.map (\a -> if condition a then b else c) x

Maybe.andThen f (Just x)
--> f x

Maybe.withDefault x Nothing
--> x

Maybe.withDefault x (Just y)
--> y

Results

Result.map identity x
--> x

Result.map f (Err x)
--> Err x

Result.map f (Ok x)
--> Ok (f x)

-- the following simplifications for map3 work for all Result.mapN
Result.map3 f (Ok a) (Ok b) (Ok c)
--> Ok (f a b c)

Result.map3 f (Ok a) (Err x) thirdResult
--> Err x

Result.map3 f firstResult (Err x) thirdResult
--> Result.map2 f firstResult (Err x)

Result.mapError identity x
--> x

Result.mapError f (Ok x)
--> Ok x

Result.mapError f (Err x)
--> Err (f x)

Result.andThen f (Err x)
--> Err x

Result.andThen f (Ok x)
--> f x

Result.andThen (\a -> Ok b) x
--> Result.map (\a -> b) x

Result.withDefault x (Err y)
--> x

Result.withDefault x (Ok y)
--> y

Result.fromMaybe x (Just a)
--> Ok a

Result.fromMaybe x Nothing
--> Err x

Result.toMaybe (Ok x)
--> Just x

Result.toMaybe (Err e)
--> Nothing

Lists

a :: []
--> [ a ]

a :: [ b ]
--> [ a, b ]

[ a ] ++ list
--> a :: list

[] ++ list
--> list

[ a, b ] ++ [ c ]
--> [ a, b, c ]

List.append [] ys
--> ys

List.append [ a, b ] [ c ]
--> [ a, b, c ]

List.head []
--> Nothing

List.head (a :: bToZ)
--> Just a

List.tail []
--> Nothing

List.tail (a :: bToZ)
--> Just bToZ

List.member a []
--> False

List.member a [ a, b, c ]
--> True

List.member a ([a, b] ++ list)
--> True

List.member a [ b ]
--> a == b

List.map f [] -- same for most List functions like List.filter, List.filterMap, ...
--> []

List.map identity list
--> list

List.map f [ a ]
--> [ f a ]

List.filter (always True) list
--> list

List.filter (always False) list
--> []

List.filterMap Just list
--> list

List.filterMap (\a -> if condition a then Just b else Just c) list
--> List.map (\a -> if condition a then b else c) list

List.filterMap (always Nothing) list
--> []

List.filterMap identity (List.map f list)
--> List.filterMap f list

List.filterMap identity [ Just x, Just y ]
--> [ x, y ]

List.filterMap identity [ a, Nothing, b ]
--> List.filterMap identity [ a, b ]

List.concat [ [ a, b ], [ c ] ]
--> [ a, b, c ]

List.concat [ a, [ 1 ], [ 2 ] ]
--> List.concat [ a, [ 1, 2 ] ]

List.concat [ a, [], b ]
--> List.concat [ a, b ]

List.concat [ a, List.concat [ b, c ], d ]
--> List.concat [ a, b, c, d ]

List.concatMap identity list
--> List.concat list

List.concatMap (\a -> [ b ]) list
--> List.map (\a -> b) list

List.concatMap f [ x ]
--> f x

List.concatMap (always []) list
--> []

List.concat (List.map f list)
--> List.concatMap f list

List.indexedMap (\_ value -> f value) list
--> List.map (\value -> f value) list

List.intersperse a []
--> []

List.intersperse s [ a ]
--> [ a ]

List.isEmpty []
--> True

List.isEmpty [ a ]
--> False

List.isEmpty (x :: xs)
--> False

List.sum []
--> 0

List.sum [ a ]
--> a

List.sum [ a, 0, b ]
--> List.sum [ a, b ]

-- when `expectNaN` is enabled
List.sum [ a, 0 / 0, b ]
--> 0 / 0

List.product []
--> 1

List.product [ a ]
--> a

List.product [ a, 1, b ]
--> List.product [ a, b ]

--  when `expectNaN` is not enabled
List.product [ a, 0, b ]
--> 0

-- when `expectNaN` is enabled
List.product [ a, 0 / 0, b ]
--> 0 / 0

List.minimum []
--> Nothing

List.minimum [ a ]
--> Just a

List.maximum []
--> Nothing

List.maximum [ a ]
--> Just a

-- The following simplifications for List.foldl also work for List.foldr
List.foldl f x []
--> x

List.foldl (\_ soFar -> soFar) x list
--> x

List.foldl (+) 0 list
--> List.sum list

List.foldl (+) initial list
--> initial + List.sum list

List.foldl (*) 1 list
--> List.product list

List.foldl (*) 0 list
--> 0

List.foldl (*) initial list
--> initial * List.product list

List.foldl (&&) True list
--> List.all identity list

List.foldl (&&) False list
--> False

List.foldl (||) False list
--> List.any identity list

List.foldl (||) True list
--> True

List.all f []
--> True

List.all (always True) list
--> True

List.all identity [ a, False, b ]
--> False

List.all not [ a, True, b ]
--> False

List.all identity [ a, True, b ]
--> List.all identity [ a, b ]

List.all not [ a, False, b ]
--> List.all not [ a, b ]

List.any f []
--> True

List.any (always False) list
--> False

List.any identity [ a, True, b ]
--> True

List.any not [ a, False, b ]
--> True

List.any identity [ a, False, b ]
--> List.any identity [ a, b ]

List.any not [ a, True, b ]
--> List.any not [ a, b ]

List.any ((==) x) list
--> List.member x list

List.range 6 3
--> []

List.length [ a, b, c ]
--> 3

List.repeat 0 x
--> []

List.repeat 1 x
--> List.singleton x

List.partition f []
--> ( [], [] )

List.partition (always True) list
--> ( list, [] )

List.partition (always False) list
--> ( [], list )

Tuple.first (List.partition f list)
--> List.filter f list

List.take 0 list
--> []

List.drop 0 list
--> list

List.drop 3 [ a, b ]
--> []

List.drop 2 [ a, b, c ]
--> [ c ]

List.reverse []
--> []

List.reverse [ a ]
--> [ a ]

List.reverse (List.reverse list)
--> list

List.sort (List.sort list)
--> List.sort list

List.sortBy (always a) list
--> list

List.sortBy identity list
--> List.sort list

List.sortBy f (List.sortBy f list)
--> List.sortBy f list

List.sortWith (\_ _ -> LT) list
--> List.reverse list

List.sortWith (\_ _ -> EQ) list
--> list

List.sortWith (\_ _ -> GT) list
--> list

-- The following simplifications for List.sort also work for List.sortBy f and List.sortWith f
List.sort []
--> []

List.sort [ a ]
--> [ a ]


-- same for up to List.map5 when any list is empty
List.map2 f xs []
--> []

List.map2 f [] ys
--> []

List.unzip []
--> ( [], [] )

Arrays

Array.fromList []
--> Array.empty

Array.fromList (Array.toList array)
--> array

Array.toList (Array.fromList list)
--> list

Array.toList Array.empty
--> []

Array.toList (Array.repeat n a)
--> List.repeat n a

Array.map f Array.empty -- same for Array.filter
--> Array.empty

Array.map identity array
--> array

Array.indexedMap (\_ value -> f value) array
--> Array.map (\value -> f value) array

Array.isEmpty Array.empty
--> True

Array.repeat 0 x
--> Array.empty

Array.initialize 0 f
--> Array.empty

Array.length Array.empty
--> 0

Array.length (Array.fromList [ a, b, c ])
--> 3

Array.length (Array.repeat 3 x)
--> 3

Array.length (Array.initialize 3 f)
--> 3

Array.length (Array.repeat n x)
--> max 0 n

Array.length (Array.initialize n f)
--> max 0 n

Array.append Array.empty array
--> array

Array.append (Array.fromList [ a, b ]) (Array.fromList [ c, d ])
--> Array.fromList [ a, b, c, d ]

Array.slice n n array
--> Array.empty

Array.slice n 0 array
--> Array.empty

Array.slice a z Array.empty
--> Array.empty

Array.slice 2 1 array
--> Array.empty

Array.slice -1 -2 array
--> Array.empty

Array.get n Array.empty
--> Nothing

Array.get 1 (Array.fromList [ a, b, c ])
--> Just b

Array.get 100 (Array.fromList [ a, b, c ])
--> Nothing

Array.get -1 array
--> Nothing

Array.get 2 (Array.repeat 10 x)
--> Just x

Array.get 100 (Array.repeat 10 x)
--> Nothing

Array.get 2 (Array.initialize 10 f)
--> Just (f 2)

Array.get 100 (Array.initialize 10 f)
--> Nothing

Array.set n x Array.empty
--> Array.empty

Array.set -1 x array
--> array

Array.set 1 x (Array.fromList [ a, b, c ])
--> Array.fromList [ a, x, c ]

Array.set 100 x (Array.fromList [ a, b, c ])
--> Array.fromList [ a, b, c ]

-- The following simplifications for Array.foldl also work for Array.foldr
Array.foldl f initial Array.empty
--> initial

Array.foldl (\_ soFar -> soFar) initial array
--> initial

Array.toIndexedList Array.empty
--> []

List.map Tuple.second (Array.toIndexedList array)
--> Array.toList array

Array.length (Array.fromList list)
--> List.length list

-- The following simplification also works for Array.toIndexedList
List.length (Array.toList array)
--> Array.length array

-- The following simplification also works for Array.toIndexedList
List.isEmpty (Array.toList array)
--> Array.isEmpty array

Sets

Set.fromList []
--> Set.empty

Set.fromList [ a ]
--> Set.singleton a

Set.fromList (Set.toList set)
--> set

Set.map f Set.empty -- same for Set.filter, Set.remove...
--> Set.empty

Set.map identity set
--> set

Set.isEmpty Set.empty
--> True

Set.isEmpty (Set.fromList ([a] ++ list)
--> False

Set.member x Set.empty
--> False

Set.toList Set.empty
--> []

Set.length Set.empty
--> 0

Set.intersect Set.empty set
--> Set.empty

Set.intersect set set
--> set

Set.diff Set.empty set
--> Set.empty

Set.diff set Set.empty
--> set

Set.union set Set.empty
--> set

Set.union set set
--> set

Set.union (Set.fromList [ a, b ]) (Set.fromList [ c, d ])
--> Set.fromList [ a, b, c, d]

Set.insert x Set.empty
--> Set.singleton x

-- same for foldr
List.foldl f x (Set.toList set)
--> Set.foldl f x set

Set.filter (\_ -> True) set
--> set

Set.filter (\_ -> False) set
--> Set.empty

Set.partition f Set.empty
--> ( Set.empty, Set.empty )

Set.partition (always True) set
--> ( set, Set.empty )

Tuple.first (Set.partition f set)
--> Set.filter f set

-- The following simplifications for Set.foldl also work for Set.foldr
Set.foldl f initial Set.empty
--> initial

Set.foldl (\_ soFar -> soFar) initial set
--> initial

List.length (Set.toList set)
--> Set.size set

List.isEmpty (Set.toList set)
--> Set.isEmpty set

Dict

Dict.fromList []
--> Dict.empty

Dict.fromList (Dict.toList dict)
--> dict

Dict.isEmpty Dict.empty
--> True

Dict.toList Dict.empty
--> []

Dict.size Dict.empty
--> 0

Dict.member x Dict.empty
--> False

Dict.remove k Dict.empty
--> Dict.empty

Dict.filter f Dict.empty
--> Dict.empty

Dict.filter (\_ _ -> True) dict
--> dict

Dict.filter (\_ _ -> False) dict
--> Dict.empty

Dict.map f Dict.empty
--> Dict.empty

Dict.map (\_ value -> value) dict
--> dict

Dict.intersect Dict.empty dict
--> Dict.empty

Dict.intersect dict dict
--> dict

Dict.diff Dict.empty dict
--> Dict.empty

Dict.diff dict Dict.empty
--> dict

Dict.union dict Dict.empty
--> dict

Dict.union dict dict
--> dict

Dict.union (Dict.fromList [ a, b ]) (Dict.fromList [ c, d ])
--> Dict.fromList [ c, d, a, b ]

Dict.partition f Dict.empty
--> ( Dict.empty, Dict.empty )

Dict.partition (\_ _ -> True) dict
--> ( dict, Dict.empty )

Dict.partition (\_ _ -> False) dict
--> ( Dict.empty, dict )

Tuple.first (Dict.partition f dict)
--> Dict.filter f dict

List.map Tuple.first (Dict.toList dict)
--> Dict.keys dict

List.map Tuple.second (Dict.toList dict)
--> Dict.values dict

-- same for foldr
Dict.foldl f initial Dict.empty
--> initial

Dict.foldl (\_ soFar -> soFar) initial dict
--> initial

-- The following simplification also works for Dict.keys, Dict.values
List.length (Dict.toList dict)
--> Dict.size dict

-- The following simplification also works for Dict.keys, Dict.values
List.isEmpty (Dict.toList dict)
--> Dict.isEmpty dict

Cmd / Sub

All of these also apply for Sub.

Cmd.batch []
--> Cmd.none

Cmd.batch [ a ]
--> a

Cmd.batch [ a, Cmd.none, b ]
--> Cmd.batch [ a, b ]

Cmd.batch [ a, Cmd.batch [ b, c ], d ]
--> Cmd.batch [ a, b, c, d ]

Cmd.map identity cmd
--> cmd

Cmd.map f Cmd.none
--> Cmd.none

Task

Task.map identity task
--> task

Task.map f (Task.fail x)
--> Task.fail x

Task.map f (Task.succeed a)
--> Task.succeed (f a)

-- the following simplifications for map3 work for all Task.mapN
Task.map3 f (Task.succeed a) (Task.succeed b) (Task.succeed c)
--> Task.succeed (f a b c)

Task.map3 f (Task.succeed a) (Task.fail x) thirdTask
--> Task.fail x

Task.map3 f firstTask (Task.fail x) thirdTask
--> Task.map2 f firstTask (Task.fail x)

Task.andThen f (Task.fail x)
--> Task.fail x

Task.andThen f (Task.succeed a)
--> f a

Task.andThen Task.succeed task
--> task

Task.andThen (\a -> Task.succeed b) task
--> Task.map (\a -> b) task

Task.mapError identity task
--> task

Task.mapError f (Task.succeed a)
--> Task.succeed a

Task.mapError f (Task.fail x)
--> Task.fail (f x)

Task.onError f (Task.succeed a)
--> Task.succeed a

Task.onError f (Task.fail x)
--> f x

Task.onError Task.fail task
--> task

Task.onError (\x -> Task.fail y) task
--> Task.mapError (\x -> y) x

Task.sequence [ Task.succeed a, Task.succeed b ]
--> Task.succeed [ a, b ]

Task.sequence [ Task.succeed a, Task.fail x ]
--> Task.fail x

Task.sequence [ a, Task.fail x, b ]
--> Task.sequence [ a, Task.fail x ]

Task.sequence [ task ]
--> Task.map List.singleton task

Html.Attributes

Html.Attributes.classList [ x, y, ( z, False ) ]
--> Html.Attributes.classList [ x, y ]

Html.Attributes.classList [ ( onlyOneThing, True ) ]
--> Html.Attributes.class onlyOneThing

Json.Decode

Json.Decode.map identity decoder
--> decoder

Json.Decode.map f (Json.Decode.fail x)
--> Json.Decode.fail x

Json.Decode.map f (Json.Decode.succeed a)
--> Json.Decode.succeed (f a)

-- the following simplifications for map3 work for all Json.Decode.mapN
Json.Decode.map3 f (Json.Decode.succeed a) (Json.Decode.succeed b) (Json.Decode.succeed c)
--> Json.Decode.succeed (f a b c)

Json.Decode.map3 f (Json.Decode.succeed a) (Json.Decode.fail x) thirdDecoder
--> Json.Decode.fail x

Json.Decode.map3 f firstDecoder (Json.Decode.fail x) thirdDecoder
--> Json.Decode.map2 f firstDecoder (Json.Decode.fail x)

Json.Decode.andThen f (Json.Decode.fail x)
--> Json.Decode.fail x

Json.Decode.andThen f (Json.Decode.succeed a)
--> f a

Json.Decode.andThen Json.Decode.succeed decoder
--> decoder

Json.Decode.andThen (\a -> Json.Decode.succeed b) decoder
--> Json.Decode.map (\a -> b) decoder

Json.Decode.oneOf [ a ]
--> a

Parser

Parser.oneOf [ a ]
--> a

Random

Random.uniform a []
--> Random.constant a

Random.weighted ( weight, a ) []
--> Random.constant a

Random.weighted tuple []
--> Random.constant (Tuple.first tuple)

Random.list 0 generator
--> Random.constant []

Random.list 1 generator
--> Random.map List.singleton generator

Random.list n (Random.constant el)
--> Random.constant (List.repeat n el)

Random.map identity generator
--> generator

Random.map (always a) generator
--> Random.constant a

Random.map f (Random.constant x)
--> Random.constant (f x)

Random.andThen f (Random.constant x)
--> f x

Random.andThen Random.constant generator
--> generator

Random.andThen (\a -> Random.constant b) generator
--> Random.map (\a -> b) generator

Random.andThen (always thenGenerator) generator
--> thenGenerator

Test

Test.concat [ test ]
--> test

Test.concat [ test0, Test.concat [ test1, test2 ], test3 ]
--> Test.concat [ test0, test1, test2, test3 ]