jfmengels / elm-review-common / NoPrematureLetComputation

rule : Review.Rule.Rule

Reports let declarations that are computed earlier than needed.

This rule is useful to prevent unnecessary computations and to group related code together.

config =
    [ NoPrematureLetComputation.rule
    ]

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

Fail

In this example, we compute value earlier than needed, and we end up not using it in of the branches.

someFunction n =
    let
        value =
            expensiveComputation n
    in
    if needToCompute then
        value + 1

    else
        0

Success

If we take the example from above, this would be the suggested (and automatic) fix:

someFunction n =
    if needToCompute then
        let
            value =
                expensiveComputation n
        in
        value + 1

    else
        0

A declaration will not be reported if it's used in multiple branches at the same level. The rule will try to move the declaration as close as possible to the usages.

someFunction n =
    let
        value =
            expensiveComputation n
    in
    if condition then
        value + 1

    else
        value - 1

Sometimes, when a computation is somewhat expensive, it is done once in a let declaration and then referenced in a let or anonymous function. This rule does not want to worsen the performance, and therefore declarations will not be moved to inside a function.

someFunction items n =
    let
        -- Will stay here
        value =
            expensiveComputation n
    in
    List.map
        (\item ->
            if condition item then
                value + item.value

            else
                0
        )
        items

There are some exceptions when we know for sure that an anonymous function will only be computed once, for instance when it is the argument to Maybe.map:

someFunction maybeItem n =
    let
        -- Will be moved from here...
        value =
            expensiveComputation n
    in
    Maybe.map
        (\item ->
            if condition item then
                -- ... to here
                value + item.value

            else
                0
        )
        maybeItem

The rule will also merge adjacent let declarations together:

someFunction n =
    let
        y =
            1
    in
    let
        z =
            1
    in
    y + z

-->
someFunction n =
    let
        y =
            1

        z =
            1
    in
    y + z

Try it out

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

elm-review --template jfmengels/elm-review-common/example --rules NoPrematureLetComputation