Proposal: `if` without `else` in List literals

In Elm, lists are special. They’re the only collection for which there’s a literal. A common need is to only sometimes include something in a collection. We’re forced to include dummy elements like text ““ inside an else.

Perhaps, when could be a keyword to distinguish this from a regular if. I have written the helper function

when : Bool -> Html msg -> Html msg
when b html = 
  if b then
    html
  else
    text ""

many times. The problem is you have to re-invent this function for every type (helper functions don’t save you much, e.g. whenHtml = whenDefault (text ““), and you might not always have a default. F# allows this. I know keeping the language small is a huge value add to Elm, however I feel an equally likely thing for beginners to stumble upon is “how do I conditionally add this HTML"? and explaining that you have to use text ““ or Html.Extra.nothing. Language support would also allow for lazy evaluation without having to wrap it in a function.

Another approach is to do

[ if cond then
      Just html
  else
      Nothing
, Just otherHtml
# etc
]
|> List.filterMap identity

This exchanges the need for a dummy element with needing to “prefix” non-conditional values with Just. There has been quite a few times that I’ve used this approach instead.

3 Likes

For doing this sort of thing we’ve also recently added List.Extra.conditional.

List.Extra.conditional 
     [ ( H.b [ ] [ H.text "Hello" ], a && b > 19 )
     , ( H.text "and", True )
     , ( H.b [] [ H.text "hi"], modBy 2 b == 0 )
     ]
9 Likes

List.Extra.conditional is so useful! Thank you!

I use the core-extra package in a lot of modules. Is there a way to add it to the default imports?

2 Likes

Not on the Elm side. You can probably configure your editor to insert the imports for you when creating a new Elm file.

I like to use a hack with display: contents;, which creates a DOM node without box hence preserving the layout (grid, flex, float) just as if the group’s div wasn’t there, its children act as if there were directly in the parent.

group : List (Html a) -> Html a
group =
    Html.div [ Html.Attributes.style "display" "contents" ]

I use this to avoid join or flatten lists of nodes ( `[…] ++ […]` ), especially in the context of large keyed lists, but can also be used as nullable (empty list).

5 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.