[erlang-questions] eep: multiple patterns

Hynek Vychodil vychodil.hynek@REDACTED
Mon May 26 19:15:10 CEST 2008


Thanks for very nice example.

On Mon, May 26, 2008 at 4:54 AM, Richard A. O'Keefe <ok@REDACTED>
wrote:

>
> On 23 May 2008, at 11:05 pm, Mats Cronqvist wrote:
>
> Hooray!  Evidence!
> >  let me assure you that there are major telecom equipment vendors
> > whose
> > code bases would benefit greatly from this syntax.
> >  although i (no longer) has access to that code, the pattern appears
> > quite often in event-driven programming. here's a very small example
> > from a simple GUI application;
> >
> > loop(St) ->
> >    receive
> >    %% user deleted top window
> >    {?MODULE,{signal,{window1,_}}}       -> quit();
> >    %% user selected quit menu item
> >    {?MODULE,{signal,{quit1,_}}}       -> quit();
> >    %% user selected  connect menu item
> >    {?MODULE,{signal,{connect,_}}}       -> loop(conn(St));
> >    %% user selected  disconnect menu item
> >    {?MODULE,{signal,{disconnect,_}}} -> loop(disc(St));
> >    %% user selected about menu item
> >    {?MODULE,{signal,{about1,_}}}       -> loop(show_about(St));
> >    %% user clicked ok in about dialog
> >    {?MODULE,{signal,{dialogb,_}}}      -> loop(hide_about(St));
> >    %% user deleted about dialog
> >    {?MODULE,{signal,{dialog1,_}}}       -> loop(hide_about(St));
> >    %% we got data from the top_top process
> >    {data,Data}                       -> loop(update(St,Data));
> >    %% quit from the erlang shell
> >    quit                              -> quit();
> >    %% log other signals
> >    X                                 -> io:fwrite("got ~p~n",
> > [X]),loop(St)
> >    end.
> >
>
> Let me start by making two changes to that code.
> The first is to indent it, so that I can read it.
> The second is to group together things with the same body.
>
>     loop(St) ->
>         receive
>            quit ->
>                %% quit from the Erlang shell
>                quit()
>          ; {?MODULE,{signal,{window1,_}}} ->
>                %% User deleted top window.
>                quit()
>          ; {?MODULE,{signal,{quit1,_}}} ->
>                %% User selected 'Quit' menu item.
>                quit()
>          ; {?MODULE,{signal,{connect,_}}} ->
>                %% User selected 'Connect' menu item.
>                loop(conn(St))
>          ; {?MODULE,{signal,{disconnect,_}}} ->
>                %% User selected 'Disconnect' menu item.
>                loop(disc(St))
>          ; {?MODULE,{signal,{about1,_}}} ->
>                %% User selected 'About' menu item.
>                loop(show_about(St))
>          ; {?MODULE,{signal,{dialogb,_}}} ->
>                %% User clicked 'OK' in "about" dialogue.
>                loop(hide_about(St))
>          ; {?MODULE,{signal,{dialog1,_}}} ->
>                %% User deleted "about" dialogue.
>          ; {data,Data} ->
>                %% We got data from the top_top process.
>                loop(update(St, Data))
>          ; X ->
>                %% Log other signals.
>                 io:fwrite("got ~p~n", [X]),
>                loop(St)
>        end.
>
> In this case, it matters that *every* message is to be received and
> acted on.  That means that we can once again use the factorisation
> technique.
>
>     loop(State) ->
>        receive
>            Message ->
>                loop(State, classify(Message))
>        end.
>
>     classify(quit)                             -> quit;
>     classify({?MODULE,{signal,{window1,_}}})   -> quit;
>     classify({?MODULE,{signal,{quit1,_}}})     -> quit;
>     classify({?MODULE,{signal,{connect,_}}})   -> connect;
>     classify({?MODULE,{signal,{disconnect,_}}})        -> disconnect;
>     classify({?MODULE,{signal,{about1,_}}})    -> show_about;
>     classify({?MODULE,{signal,{dialog1,_}}})   -> hide_about;
>     classify({?MODULE,{signal,{dialogb,_}}})   -> hide_about;
>     classify({data,Data})                      -> {data,Data};
>     classify(X)                                        -> {error,X}.
>
>     loop(_, quit) ->
>        quit();
>     loop(State, connect) ->
>        loop(conn(State));
>     loop(State, disconnect) ->
>        loop(disc(State));
>     loop(State, show_about) ->
>        loop(show_about(State));
>     loop(State, hide_about) ->
>        loop(hide_about(State));
>     loop(State, {data,Data}) ->
>        loop(update(State, Data));
>     loop(State, {error,X}) ->
>         io:fwrite("got ~p~n", [X]),
>         loop(State).
>
> I like this because it makes a clean separation between
> "what are the actions" and "what are the names for the actions".
>
> Of course you can in-line this.  Just as we can have
> case/case, we can have case/receive, getting
>
>     loop(State) ->
>        case receive
>                 quit                              -> quit
>               ; {?MODULE,{signal,{window1,_}}}    -> quit
>               ; {?MODULE,{signal,{quit1,_}}}      -> quit
>               ; {?MODULE,{signal,{connect,_}}}    -> connect
>               ; {?MODULE,{signal,{disconnect,_}}} -> disconnect
>               ; {?MODULE,{signal,{about1,_}}}     -> show_about
>               ; {?MODULE,{signal,{dialog1,_}}}    -> hide_about
>               ; {?MODULE,{signal,{dialogb,_}}}    -> hide_about
>               ; {data,Data}                       -> {data,Data}
>               ; X                                 -> {error,X}
>             end
>          of quit       -> quit()
>           ; connect    -> loop(conn(State))
>           ; disconnect -> loop(disc(State))
>           ; show_about -> loop(show_about(State))
>           ; hide_about -> loop(hide_about(State))
>           ; {data,D}   -> loop(update(State, D))
>           ; {error,X}  -> io:fwrite("got ~p~n", [X]),
>                           loop(State)
>        end.
>
> Now my first reaction on seeing a whole raft of {?MODULE,{signal,
> {Foo,_}}}
> patterns was "this is too hard for me to read".  I would be trying to
> simplify the protocol.  Separating the receive protocol from the action
> selection makes this kind of maintenance easier.  Inlining means that
> the versions with separate functions and with nested case/receive are
> operationally equivalent.  A few hacks in the compiler could produce
> essentially the same code as the original version, although I doubt that
> it would be worth bothering.
>
> Tastes vary.  To me, what we can write now in Erlang as it stands,
> separating "what are the actions" from "what are the names for the
> actions",
> is easier to read and understand than anything using multiple patterns
> would be, not because multiple patterns are a bad idea as such, but
> because
> combining multiple *complex* patterns into a single match makes the code
> harder to read.  Multiple *simple* patterns might make for a more
> interesting example.
>
> --
> "I don't want to discuss evidence." -- Richard Dawkins, in an
> interview with Rupert Sheldrake.  (Fortean times 232, p55.)
>
>
>
>
>
>
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://www.erlang.org/mailman/listinfo/erlang-questions
>



-- 
--Hynek (Pichi) Vychodil
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20080526/a0a93cbf/attachment.htm>


More information about the erlang-questions mailing list