Matching fun M:F/A

Mikael Pettersson mikpelinux@REDACTED
Thu Jan 2 10:28:05 CET 2020


On Tue, Dec 31, 2019 at 5:12 PM Pierre Fenoll <pierrefenoll@REDACTED> wrote:
>
> Hi,
>
> Since a few releases, the value fun M:F/A (provided M, F & A are bound) is a literal. It can be read with file:consult/1 as well as erlang:binary_to_term/1.
>
> Running OTP 22, funs can be compared:
>
> eq(F) ->
>     %% Compiles & works as expected.
>     F == fun lists:keysearch/3.
>
> However MFAs cannot be matched:
>
> %% syntax error before: 'fun'
> fmatch(fun lists:keysearch/3) -> true;
> fmatch(_) -> false.
>
> cmatch(F) ->
>     case F of
>         %% illegal pattern
>         fun lists:keysearch/3 -> true;
>         %% illegal guard expression
>         X when X == fun lists:keysearch/3 -> true;
>
>         %% illegal pattern
>         fun lists:_/3 -> inte;
>         fun _:handle_cast/2 -> resting;
>         _ -> false
>     end.
>
> Is this intended?
>
> I believe it would be interesting to allow such patterns as well as for fun _:_/_.
> This could help in optimization through specialization and probably would make for some new approaches.
> Among all funs only fully qualified funs can be expressed this way so this behaviour could be a bit surprising to some but MFAs are already comparable today so I'd say we're already halfway there.

I believe this is mostly a historical accident.  Erlang started out as
a first-order language, and functional values were a later addition
(made in several increments I believe).  Also, functional values are
mostly opaque while pattern-matching is entirely about determining the
shape of non-opaque types, so I'm not surprised that fun M:F/A like
patterns aren't supported.

Having said that, there's no inherent reason why fun M:F/A couldn't be
a pattern, but the effort required to implement it would be
substantial, and I question how much real-world value it would
provide.

A slightly |ower-cost alternative that would still be useful would be
to make fun_info/2 a guard BIF, but in that case it should return the
requested value directly and not wrapped as a {Key,Value} tuple.  The
old is_function(F, A) would then be an alias for is_function(F),
fun_info(F, arity) == A.



More information about the erlang-questions mailing list