Can I pattern match without a case expression?

I’m drawing my sidebar links like this:

[ viewSidebarLink "/" "Dashboard" "fa-house" (model.page == Dashboard)
, viewSidebarLink "/my-forms" "My Forms" "fa-list" (model.page == MyForms)
, viewSidebarLink "/settings" "Settings" "fa-gear" (model.page == Settings)
]

-- ...

viewSidebarLink : String -> String -> String -> Bool -> Html.Html Msg
viewSidebarLink linkTarget linkText icon active =
    ...

This works as long as none of my pages take any extra data:

type Page
    = Dashboard
    | MyForms
    | Settings
    | Error404

However, I want to flesh out my pages, adding extra state for the dashboard, for example:

type Page
    = Dashboard DashboardState
    | MyForms
    | Settings
    | Error404

Now the code for drawing my sidebar links breaks, because I can no longer do (model.page == Dashboard), instead I have to do this awful, ugly, verbose monstrosity:

[ viewSidebarLink "/"
    "Dashboard"
    "fa-house"
    (case model.page of
        Dashboard _ ->
            True

        _ ->
            False
    )
, viewSidebarLink "/my-forms" "My Forms" "fa-list" (model.page == MyForms)
, viewSidebarLink "/settings" "Settings" "fa-gear" (model.page == Settings)
]

Does Elm have any way to check if an expression matches a pattern without doing a full blown case expression?

It seems extremely verbose to use a case expression for this use case, it seems like there should be a shortcut for this, such as (case model.page of Dashboard _).

Or am I using a bad pattern here, is there a better way to achieve the same result? (i.e. check which “branch” of the state I’m in, ignoring any data underneath)

No, there is no way to do a non-verbose partial match on an expression in Elm (except for using equality as you have demonstrated). For this situation, I might introduce a new type to model the active state, for example:

let
  activeDefaults =
    { dashboard = False
    , myForms = False
    , settings = False
    }
  active =
    case model.page of
      Dashboard _ ->
        { activeDefaults | dashboard = True }
      MyForms ->
        { activeDefaults | myForms = True }
      Settings ->
        { activeDefaults | settings = True }
in
[ viewSidebarLink "/" "Dashboard" "fa-house" active.dashboard
, viewSidebarLink "/my-forms" "My Forms" "fa-list" active.myForms
, viewSidebarLink "/settings" "Settings" "fa-gear" active.settings
]
1 Like

What about testing equality on the URL path ? For example:

-- This might be useful somewhere else
pageToPath page =
 case page of
    Dashboard _ ->
      "/"
    MyForms ->
      "/my-forms"

viewSidebarLinks model =
  [ viewSidebarLink "/" "Dashboard" "fa-house" ("/" == pageToPath model.page)
  -- ...
  ]

Another unsurprising solution is to just write helper functions like this one:

isDashboard page = 
    case page of
        Dashboard _ ->
            True

        _ ->
            False

Given that you might need those anyway somewhere else in the application. :slight_smile:

2 Likes

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