3
\$\begingroup\$

I am trying to solve some exercises from the "Programming Erlang" book.

One of them is "Write a function to determine which module exports the most functions"

This is my solution:

-module(module_info).
-export([modules_ordered_by_amount_of_functions/0]).
modules_ordered_by_amount_of_functions() ->
 Modules = loaded_modules_with_functions(),
 SortedModules = lists:sort(fun compare_functions_length/2, Modules),
 lists:map(fun extract_amount_of_functions/1, SortedModules).
loaded_modules_with_functions() ->
 LoadedModules = code:all_loaded(),
 LoadedModuleNames = lists:map(fun extract_module_name/1, LoadedModules),
 lists:map(fun extract_functions_from_module/1, LoadedModuleNames).
extract_module_name({ModuleName, _}) -> ModuleName.
extract_functions_from_module(ModuleName) ->
 [_, {exports, Functions} | _] = ModuleName:module_info(),
 {ModuleName, Functions}.
compare_functions_length ({_, FunctionsA}, {_, FunctionsB}) ->
 length(FunctionsA) >= length(FunctionsB).
extract_amount_of_functions ({ModuleName, Functions}) ->
 {ModuleName, length(Functions)}.

It doesn't really feel elegant to me.

200_success
146k22 gold badges190 silver badges479 bronze badges
asked Jun 4, 2018 at 20:01
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Breaking the problem into tiny, useful functions is a very good way to write Erlang code. So your code is easy to read and gives us a great start in understanding and analyzing it.

The one thing I notice is that, in loaded_modules_with_functions, you map a function over a list and then map a function on the resulting list. This creates an intermediate list which will just be thrown away (GCed.) I'd combine the two operations so there's only one pass through the list. Since the result of this function is the resulting list, I'd use a list comprehension:

loaded_modules_with_functions() ->
 [ extract_functions_from_module(ModName) || {ModName, _} <- code:all_loaded() ].

In extract_functions_from_module, you're making an assumption that the export list is always the second element. Maybe this is the case. Or maybe in your OTP release this is always the case. The next release, however, may break your code if module_info adds more information. You can use the proplists module (in the standard library) to generalize the look-up:

extract_functions_from_module(ModuleName) ->
 {ModuleName, proplists:get_value(exports, ModuleName:module_info(), [])}.

Finally, I'd put a list comprehension at the end of modules_ordered_by_amount_of_functions and inline extract_amount_of_functions.

answered Jun 11, 2018 at 17:07
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.