elm / compiler

Compiler for Elm, a functional language for reliable webapps.
https://elm-lang.org/
BSD 3-Clause "New" or "Revised" License
7.51k stars 656 forks source link

Feature: Pattern matching in function definitions #1671

Closed sezaru closed 6 years ago

sezaru commented 6 years ago

Using the Elm Architecture, normally the component's update function will grow as the same pace as new messages are added to it.

That means that we normally see code like this:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Message1 ->
            ... Handle Message1 ...
        Message2 arg1 ->
            ... Handle Message2 ...
        Message3 arg1 arg2 ->
            ... Handle Message3 ...
        Message4 ->
            ... Handle Message4 ...
        _ ->
            ... Handle otherwise ...

My proposal is to be able to do pattern matching directly in the function definition, so we can break the update function in smaller, non-conditional and easier to test functions:

update : Msg -> Model -> ( Model, Cmd Msg )
update Message1 model =
    ... Handle Message1 ...

update (Message2 arg1) model =
    ... Handle Message2 ...

update (Message3 arg1 arg2) model =
    ... Handle Message3 ...

update Message4 model =
    ... Handle Message4 ...

update msg model =
    ... Handle otherwise ...

Note that I'm fairly new to the language and I'm not sure if this syntax would be possible/valid, but coming from Elixir, the function definition pattern match was the first thing I missed in Elm.

process-bot commented 6 years ago

Thanks for the issue! Make sure it satisfies this checklist. My human colleagues will appreciate it!

Here is what to expect next, and if anyone wants to comment, keep these things in mind.

50kudos commented 6 years ago

That is what MFC or Qt does. It's nice that every event has its own function handler. But I have no idea how these are going to wire back up with the main program. It might end up just hiding that main update function, and that's not going to improve thing much. 🍨

sezaru commented 6 years ago

Do you mean how we would add the update functions to main like that:

main =
  Html.program
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    }

Right?

Well, since all the updates functions have the same definition update : Msg -> Model -> ( Model, Cmd Msg ) only differing in the pattern matching of the Msg type, my guess is that the compiler could convert it to a single function using case of.

So we still just need to add one update function to the main like we do now.

Would that be possible?

I think this is what Elixir does behind the scenes, the Erlang VM try to match all the functions with the same name, arity and type from top to bottom and execute the matched one.

The nice thing is that this is totally transparent to the developer.

sezaru commented 6 years ago

Also, the idea of function signature pattern matching goes way beyond the update function, i just used it as an example because it was a obvious one to me.

But if we can have pattern matching for lists contents, strings, etc. We can reduce a lot of complicated conditional code in functions like:

doSomething : List String -> String
doSomething = []
    -- Empty list
    ...

doSomething = [a]
    -- List with one string a, get a
    ...

doSomething = a::_
    -- List with more than one string, get a
    ...
zwilias commented 6 years ago

Multiple definitions with implicit pattern matching, while theoretically possible, is not something I think Evan would like to add to Elm. His style-guide for Haskell code (which does support that particular feature) outlines some of the reasons.

More importantly, the issues are for bugs, not feature proposals.