List Comprehensions
As I was trekking through yaws country, I realized the value that the recent(sort of) feature of list comprehensions are. I'm still getting used to them all the time. I find myself writing a recursive function to iterate over data using some of the functions in the lists module, or even forgetting about map, fold(l|r) etc...
I was writing a page that contacts an erlang node in order to display memory data for the VM.
The function to get the remote data is:
I use the most excellent rpc module to easily execute a remote method call to a remote erlang node, the name of which is passed in as a parameter.
What I wanted to do with this page is to output the memory information in a simple table. In order to do this in yaws, I wrote an tag that outputs this information dynamically.
<erl>
</erl>
Notice that I'm using the form library;)
What I did initially was this:
This function gets the memory data and loops over the list to create a tr and two td tags for each memory statistic. It uses lists:map to do this
But then I remembered list comprehensions. I then wrote:
I've highlighted the list comprehension line of code. Now I don't have to define my own anonymous fun.
Is there any difference? Sematically, no I don't believe, but I think you will find that list comprehensions will simplify list iteration code in the long run. They are used in qlc queries too.
I will cover qlc and mnesia in another blog entry. I thought that I should put another yaws entry out there before I go on to postgresql and mnesia.
One more thing, I did write a parameter validation block using the form validation library, which I placed before the memory output block. Here it is:
<erl>
out(A) ->
</erl>
Returning ok from an out function is a noop. It does nothing and continues the page. If there is an error, a cryptic programmer-friendly error message is displayed and the page processing is stopped via the break atom.
See you next time.
I was writing a page that contacts an erlang node in order to display memory data for the VM.
The function to get the remote data is:
get_memory_data(Server) ->
case rpc:call(Server, erlang, memory, []) of
{badrpc, Reason} ->
{error, Reason};
Data ->
{ok, Data}
end.
I use the most excellent rpc module to easily execute a remote method call to a remote erlang node, the name of which is passed in as a parameter.
What I wanted to do with this page is to output the memory information in a simple table. In order to do this in yaws, I wrote an
<erl>
out(A) ->
Data = yaws_api:parse_query(A),
{ok, Server} = wsform:get_value_atom("server", Data),
{ehtml, output_memory(Server)}.
</erl>
Notice that I'm using the form library;)
What I did initially was this:
output_memory(Server) ->
case get_memory_data(Server) of
{ok, Data} ->
Fun = fun({Name, Value}) ->
{tr, [], [{td, [], f("~p", [Name])},
{td, [], f("~p", [Value])}]}
end,
Rows = lists:map(Fun, Data),
{'div', [{style, "float: left; padding-right: 10px;"}],
{table, [], [{tr, [], {td, [{colspan, "2"}], "Memory Stats"}},
Rows]}};
{error, Reason} ->
{p, [], f("No memory data: ~p", [Reason])}
end.
This function gets the memory data and loops over the list to create a tr and two td tags for each memory statistic. It uses lists:map to do this
But then I remembered list comprehensions. I then wrote:
output_memory(Server) ->
case get_memory_data(Server) of
{ok, Data} ->
Rows = [{tr, [], [{td, [{class,"dataHeader"}], f("~p", [Name])},
{td, [], f("~p", [Value])}]} || {Name, Value} <- Data],
{'div', [{style, "float: left; padding-right: 10px;"}],
{table, [], [{tr, [], {td, [{colspan, "2"}, {class, "twocolDataHeader"}], "Memory Stats"}},
Rows]}};
{error, Reason} ->
{p, [], f("No memory data: ~p", [Reason])}
end.
I've highlighted the list comprehension line of code. Now I don't have to define my own anonymous fun.
Is there any difference? Sematically, no I don't believe, but I think you will find that list comprehensions will simplify list iteration code in the long run. They are used in qlc queries too.
I will cover qlc and mnesia in another blog entry. I thought that I should put another yaws entry out there before I go on to postgresql and mnesia.
One more thing, I did write a parameter validation block using the form validation library, which I placed before the memory output block. Here it is:
<erl>
out(A) ->
Rules = [{"server", [required]}],
Data = yaws_api:parse_query(A),
case wsform:validate_page_data(Data, Rules) of
ok ->
ok;
Error ->
[{html, f("Invalid data: ~p ~p", [Error, Data])},
break]
end.
</erl>
Returning ok from an out function is a noop. It does nothing and continues the page. If there is an error, a cryptic programmer-friendly error message is displayed and the page processing is stopped via the break atom.
See you next time.

2 Comments:
Nicely done. I find that my best learning coming from the non-Erlang world is through seeing such refactoring (well this might be technically another concept, but it is similar enough for me). I see how I would do it, and how it could be done better, and I learn. Thanks!
By
Anonymous, at 3:53 PM
If you are using the ehtml module of the yfront application in jungerl; then you could have written
something like this:
case get_memory_data() of
{ok, Data} ->
ehtml:table([[Name,Value] || {Name,Value} <- Data]);
...
Then put this within a 'div' and use some CSS to make it look the way you like.
By
Anonymous, at 6:48 AM
Post a Comment
<< Home