1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!-- This document was generated using DocBuilder 3.3.3 -->
<HTML>
<HEAD>
<TITLE>Functions</TITLE>
<SCRIPT type="text/javascript" src="../../doc/erlresolvelinks.js">
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#FF00FF"
ALINK="#FF0000">
<CENTER>
<A HREF="http://www.erlang.se"><IMG BORDER=0 ALT="[Ericsson AB]" SRC="min_head.gif"></A>
</CENTER>
<A NAME="3"><!-- Empty --></A>
<H2>3 Functions</H2>
<A NAME="3.1"><!-- Empty --></A>
<H3>3.1 Pattern matching</H3>
<P> Pattern matching in function, case and receive-clauses are
optimized by the compiler. In most cases, there is nothing
to gain by rearranging clauses.<A NAME="3.2"><!-- Empty --></A>
<H3>3.2 Function Calls </H3>
<P>A function can be called in a number of ways and the cost
differs a lot. Which kind of call to use depends on the
situation. Below follows a table with the available alternatives and
their relative cost.
<P>
<TABLE CELLPADDING=4>
<TR>
<TD VALIGN=TOP><IMG ALT="Note!" SRC="note.gif"></TD>
<TD>
<P> The figures shown as relative cost is highly dependent on
the implementation and will vary between versions and platform. The
order from lowest to highest cost will however be stable and is very
useful to be aware of. </TD>
</TR>
</TABLE>
<P>
<CENTER>
<TABLE CELLSPACING=0 CELLPADDING=2 BORDER=1>
<CAPTION ALIGN=BOTTOM><EM>Different ways of calling a function</EM></CAPTION>
<TR>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Type of call
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Example
</TD>
<TD ALIGN="CENTER" VALIGN="MIDDLE">
Relative cost<BR>
(5.4)
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
Local call
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE>foo()</CODE>
</TD>
<TD ALIGN="RIGHT" VALIGN="MIDDLE">
1.00
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
External call
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE>m:foo()</CODE>
</TD>
<TD ALIGN="RIGHT" VALIGN="MIDDLE">
1.08
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
Fun call
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE>Fun = fun(X) -> X + 1 end, Fun(2)</CODE>
</TD>
<TD ALIGN="RIGHT" VALIGN="MIDDLE">
2.79
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
Apply fun
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE>Fun = fun(X) -> X + 1 end, apply(Fun,[2])</CODE>
</TD>
<TD ALIGN="RIGHT" VALIGN="MIDDLE">
3.54
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
Implicit apply
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE>M:Foo()</CODE>
</TD>
<TD ALIGN="RIGHT" VALIGN="MIDDLE">
7.76
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
Apply MFA/3
</TD>
<TD ALIGN="LEFT" VALIGN="MIDDLE">
<CODE>apply(M, Foo, [])</CODE>
</TD>
<TD ALIGN="RIGHT" VALIGN="MIDDLE">
8.21
</TD>
</TR>
</TABLE>
</CENTER>
<P> Apply is the most expensive way to call a function and
should be avoided in time critical code. A well motivated use of
apply is in conjunction with generic interfaces where several
modules provide the same set of functions.
<P>
<TABLE CELLPADDING=4>
<TR>
<TD VALIGN=TOP><IMG ALT="Note!" SRC="note.gif"></TD>
<TD>
<P> The syntax <CODE>M:Foo(A1,A2,An)</CODE> (also referred to as
implicit apply, where M and Foo are bound variables) where
equivalent with <CODE>apply(M,Foo,[A1,A2,An])</CODE> in releases pre
OTP-R10B. The compiler will now optimize this syntax giving it
better performance than apply/3. </TD>
</TR>
</TABLE>
<P>The use of <CODE>apply/3</CODE> for just calling different functions
within the same module (i.e <CODE>apply(mymodule,Func,Args)</CODE>) is
not recommended. The use of Funs can often be a more efficient
way to accomplish calls which are variable in runtime.
<A NAME="3.3"><!-- Empty --></A>
<H3>3.3 Memory usage in recursion</H3>
<P>When writing recursive functions it is preferable to make them
tail-recursive so that they can execute in a constant memory space.
<P><STRONG>DO</STRONG>
<PRE>
list_length(List) ->
list_length(List, 0).
list_length([], AccLen) ->
AccLen; % Base case
list_length([_|Tail], AccLen) ->
list_length(Tail, AccLen + 1). % Tail-recursive
</PRE>
<P><STRONG>DO NOT</STRONG>
<PRE>
list_length([]) ->
0. % Base case
list_length([_ | Tail]) ->
list_length(Tail) + 1. % Not tail-recursive
</PRE>
<A NAME="3.4"><!-- Empty --></A>
<H3>3.4 Unnecessary evaluation in each recursive step</H3>
<P> Do not evaluate the same expression in each recursive step,
rather pass the result around as a parameter. For example
imagine that you have the function in_range/3 below and want to write
a function in_range/2 that takes a list of integers and atom as
argument. The atom specifies a key to the named table
range_table, so you can lookup the max and min values for a
particular type of range.
<PRE>
in_range(Value, Min, Max) ->
(Value >= Min) and (Value =< Max).
</PRE>
<P><STRONG>DO</STRONG>
<PRE>
in_range(ValuList, Type) ->
%% Will be evaluated only one time ...
[{Min, Max}] = ets:lookup(range_table, Type),
%% ... send result as parameter to recursive help-function
lists_in_range(ValuList, Min, Max).
lists_in_range([Value | Tail], Min, Max) ->
case in_range(Value, Min, Max) of
true ->
lists_in_range(Tail, Min, Max);
false ->
false
end;
lists_in_range([], _, _) ->
true.
</PRE>
<P><STRONG>DO NOT</STRONG>
<PRE>
in_range([Value | Tail], Type) ->
%% Will be evaluated in each recursive step
[{Min, Max}] = ets:lookup(range_table, Type),
case in_range(Value, Min, Max) of
true ->
lists_in_range(Tail, Type);
false ->
false
end;
in_range([], _, _) ->
true.
</PRE>
<CENTER>
<HR>
<SMALL>
Copyright © 1991-2006
<A HREF="http://www.erlang.se">Ericsson AB</A><BR>
</SMALL>
</CENTER>
</BODY>
</HTML>
|