Last active
August 24, 2019 10:21
-
-
Save garazdawi/fed00fa0939624ae8109530afaeb50dd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%% Introducing the new `apply` pattern match operand. | |
%% `apply` is used to delegate the handling of a match | |
%% to some other function including the action to be taken | |
%% when a successful match happens. The `apply` statement | |
%% replaces the "-> body" part of a function/case/receive. | |
%% | |
%% Simple example: | |
%% example() -> | |
%% Pat = fun(A) when is_atom(A) -> | |
%% {ok, A} | |
%% end, | |
%% example(Pat). | |
%% | |
%% example(Pat) -> | |
%% receive | |
%% Msg apply Pat(Msg) | |
%% end. | |
%% | |
%% This example creates a fun that is used at the pattern for | |
%% a receive in another function. Only messages that match | |
%% any clause in the fun will be received. | |
-module(funmatch). | |
-export([test/1, gen_server_test/0, match_many_dynamic/0]). | |
%% Small basic example | |
test(Parent) -> | |
%% Handle system messages and parent shutdown | |
Fun = fun({system, From, Msg}) -> | |
sys:handle_system_msg(Msg, From, Parent, ?MODULE, | |
[], [], false); | |
({'EXIT', P, Reason}) when P =:= Parent -> | |
exit(Reason) | |
end, | |
%% Use fun as match in a receive | |
receive | |
SysMsg apply Fun(SysMsg); | |
AnyMsg -> AnyMsg | |
end, | |
%% Use fun as match in a case | |
case hello of | |
Msg apply Fun(Msg); | |
hello -> ok | |
end. | |
%% An example of how it could be used in a gen_server like implementation | |
%% in order to do selective receives. | |
gen_server_test() -> | |
gen_server_test(0, fun handle_cast/2, fun handle_call/3). | |
gen_server_test(State, CastPat, CallPat) -> | |
%% Here we use a fun as part of the `when` in a match, this allows us | |
%% to transform some of the arguments and add some context to the calls. | |
%% Note that the messages are not matched unless both the receive | |
%% and handle_cast/call matched. | |
R = receive | |
{'$gen_cast', Msg} apply CastPat(Msg, State); | |
{'$gen_call', From, Msg} apply CallPat(Msg, From, State) | |
end, | |
case R of | |
{noreply, NewState} -> | |
gen_server_test(NewState, CastPat, CallPat); | |
{reply, Reply, NewState} -> | |
From ! Reply, | |
gen_server_test(NewState, CastPat, CallPat) | |
end. | |
%% if more then 10 incr calls are made, the increments are left in the | |
%% message queue of the process until a decr request comes along. | |
handle_cast(incr, State) when State < 10 -> | |
{noreply, State + 1}; | |
handle_cast(decr, State) when State > 0 -> | |
{noreply, State - 1}. | |
handle_call(get, _From, State) -> | |
{reply, State, State}. | |
%% An example of how dynamic pattern matching in function heads might work | |
%% Match many_dynamic/1 could of course also be applied from a receive | |
%% clause. | |
match_many_dynamic() -> | |
Pats = [fun isatom/1, fun isnumber/1], | |
{atom, hello} = match_many_dynamic(Pats, hello), | |
{number, 123} = match_many_dynamic(Pats, 123), | |
{unexpected, []} = match_many_dynamic(Pats, []). | |
%% So this is kind of creepy and dangerous, recursive dynamic pattern matching. | |
%% If the pattern in the head of the list matches we run it, | |
%% otherwise if there is a tail we recursively match using the tail of the list. | |
%% If there is no match in the list of patterns we return {unexpected, Msg}. | |
%% | |
%% This of course means that we can have infinite recursive pattern matching | |
%% which may be a problem? | |
match_many_dynamic([HPat|_], Msg) apply HPat(Msg); | |
match_many_dynamic([_|TPat], Msg) apply match_many_dynamic(TPat, Msg); | |
match_many_dynamic([], Msg) -> | |
{unexpected, Msg}. | |
isatom(Atom) when is_atom(Atom) -> | |
{atom, Atom}. | |
isnumber(Number) when is_number(Number) -> | |
{number, Number}. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment