jfmengels/elm-review-simplify/2.0.27

NOTE: the latest version is 2.1.15

Simplify

Reports when an expression can be simplified.

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

config =
    [ Simplify.rule Simplify.defaults
    ]

Rule to simplify Elm code.

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

Default configuration for this rule. Use ignoreCaseOfForTypes if you want to change the configuration.

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

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

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

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

Basics functions

identity x
--> x


f >> identity
--> f


always x y
--> x


f >> always x
--> always x

Lambdas

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


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


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

Operators

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

Numbers

n + 0
--> n


n - 0
--> n


0 - n
--> -n


n * 1
--> n


n / 1
--> n


-(-n)
--> n


negate (negate n)
--> n

Strings

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


String.fromList []
--> ""


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


String.isEmpty ""
--> True


String.isEmpty "a"
--> False


String.concat []
--> ""


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.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
--> ""

Maybes

Maybe.map identity x
--> x


Maybe.map f Nothing
--> Nothing


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


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)


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

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 [ b ]
--> a == b


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


List.map identity list
--> list


List.filter (\a -> 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.concat [ [ a, b ], [ c ] ]
--> [ a, b, c ]


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


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


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


List.concatMap fn [ x ]
--> fn 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.isEmpty []
--> True


List.isEmpty [ a ]
--> False


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


List.sum []
--> 0


List.sum [ a ]
--> a


List.product []
--> 1


List.product [ a ]
--> a


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 fn 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 fn []
--> True


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


List.any fn []
--> True


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


List.range 6 3
--> []


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


List.repeat 0 x
--> []


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


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


List.take 0 list
--> []


List.drop 0 list
--> list


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


List.sortBy (\_ -> a) list
--> list


List.sortBy identity list
--> List.sort 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 fn and List.sortWith fn
List.sort []
--> []


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


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


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


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

Sets

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


Set.map identity set
--> set


Set.isEmpty Set.empty
--> True


Set.member x Set.empty
--> False


Set.fromList []
--> Set.empty


Set.toList Set.empty
--> []


Set.length Set.empty
--> 0


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


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


Set.diff set Set.empty
--> set


Set.union set Set.empty
--> set


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


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


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


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

Dict

Dict.isEmpty Dict.empty
--> True


Dict.fromList []
--> Dict.empty


Dict.toList Dict.empty
--> []


Dict.size Dict.empty
--> 0


Dict.member x Dict.empty
--> False

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.map identity cmd
--> cmd


Cmd.map fn Cmd.none
--> Cmd.none

Json.Decode

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

Parser

Parser.oneOf [ a ]
--> a