[erlang-questions] Functions with same name and varying arity using apply

Ryan Huffman <>
Thu Jan 20 06:59:49 CET 2011


If you really don't want to export, you could try something like this:

-module(test).
-export([bar/2]).

-define(BARRABLE_FUNS, [{{foo, 1}, fun foo/1},
		                {{foo, 2}, fun foo/2}]).
			
get_fun(F, X) ->
	proplists:get_value({F, length(X)}, ?BARRABLE_FUNS).

foo(A) -> A.
foo(A, B) -> A + B.

bar(_, []) -> [];
bar(F, [X|Xs]) -> [apply(get_fun(F, X), X) | bar(F, Xs)].




On Wed, Jan 19, 2011 at 7:51 PM, Steve Vinoski <> wrote:
> On Wed, Jan 19, 2011 at 9:44 PM, Taylor Venable <> wrote:
>>
>> Sorry, I could have been more clear; I'm very early in the process of
>> learning Erlang and was writing my first "real" program when I
>> encountered this. Basically, I want to dynamically apply functions
>> which I've defined inside a module, which have the same name but take
>> different numbers of arguments. If possible, I want to do it without
>> exporting those "helper" functions (in this case foo/1 and foo/2).
>> Perhaps a better example would be if foo/2 accepted a list of options
>> that affected its behaviour, and foo/1 is just calling foo/2 with an
>> empty option list:
>>
>> %% test.erl
>>
>> -module(test).
>> -export([foo/1,foo/2,bar/2]).
>>
>> foo(A) -> foo(A, []).
>> foo(A, Options) ->
>>    case lists:member(double, Options) of
>>        true -> A * 2;
>>        false -> A
>>    end.
>>
>> bar(_, []) -> [];
>> bar(F, [X|Xs]) -> [apply(test, F, X) | bar(F, Xs)].
>>
>> %% END
>>
>> With this method, foo/1 and foo/2 have to be exported due to how
>> apply/3 works (I assume; that's what the documentation says, and it
>> fails if you don't export them).
>
> If you don't export them, the compiler will think they're unused and
> won't include them in the generated beam file, in which case they
> obviously won't be around to call by any means.
>
>> If I try using apply/2 then that
>> takes a function, rather than an atom, so I have to do something like:
>>
>> bar(fun foo/1, [[1], [2, [double]]]) % from inside the module
>>
>> Which is not a solution because I have to declare up front whether to
>> use foo/1 or foo/2, the opposite of what I'm trying to accomplish. So
>> I was wondering if there was another approach to make it work.
>
> You might consider just always passing a single list argument to foo,
> so there's just one to export. It could work like this:
>
> -module(test).
> -export([foo/1, bar/2]).
>
> foo([A]) -> foo([A, []]);
> foo([A, Options]) ->
>   case lists:member(double, Options) of
>       true -> A * 2;
>       false -> A
>   end.
>
> bar(_, []) -> [];
> bar(F, [X|Xs]) -> [?MODULE:F(X) | bar(F, Xs)].
>
> Then you could call it like this:
>
> test:bar(foo, [[1], [2, [double]]]).
>
> which is the same as you showed earlier. I get [1, 4] from this call,
> as expected.
>
>> The context of discovering this is that in my program I receive the
>> arguments to foo (in my example: both [1] and [2, [double]]) from the
>> user by way of reading terms (I think that's the right word; I'm
>> reading a list of atoms and tuples and such from a file
>
> Using file:consult/1, I hope?
>
>> and then using
>> them to direct what the program does, like a very simple specification
>> of commands; like what one does in Lisp reading a sexp).
>
> Another option along the Lisp reader line would be to read the user's
> terms, and based on those terms first generate "code as data" in
> Abstract Format as a set of terms, then compile it and load the
> resulting beam on the fly, and finally invoke one of the newly-loaded
> functions. Look up Abstract Format in the erts manual and also see the
> compile module and the beam_lib module. Whether it's worth it to go to
> this extent depends on how often the code would be invoked -- if
> you're writing some sort of DSL that's read once and then invoked
> numerous times, this approach could be worth it.
>
> --steve
>
> ________________________________________________________________
> erlang-questions (at) erlang.org mailing list.
> See http://www.erlang.org/faq.html
> To unsubscribe; mailto:
>
>


More information about the erlang-questions mailing list