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 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
|
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<!-- %% -->
<!-- %W function.tex GAP documentation Thomas Breuer -->
<!-- %W & Frank Celler -->
<!-- %W & Martin Schönert -->
<!-- %W & Heiko Theißen -->
<!-- %% -->
<!-- %H @(#)<M>Id: function.tex,v 4.13 2001/10/06 18:32:31 gap Exp </M> -->
<!-- %% -->
<!-- %Y Copyright 1997, Lehrstuhl D für Mathematik, RWTH Aachen, Germany -->
<!-- %% -->
<!-- %% This file contains a tutorial introduction to functions. -->
<!-- %% -->
<P/>
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<Chapter Label="Functions">
<Heading>Functions</Heading>
You have already seen how to use functions in the &GAP; library,
i.e., how to apply them to arguments.
<P/>
In this section you will see how to write functions in the &GAP;
language. You will also see how to use the <K>if</K> statement and declare
local variables with the <K>local</K> statement in the function definition.
Loop constructions via <K>while</K> and <K>for</K> are discussed further, as are
recursive functions.
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<Section Label="Writing Functions">
<Heading>Writing Functions</Heading>
<P/>
Writing a function that prints <C>hello, world.</C> on the screen is a simple
exercise in &GAP;.
<P/>
<Example><![CDATA[
gap> sayhello:= function()
> Print("hello, world.\n");
> end;
function( ) ... end
]]></Example>
<P/>
This function when called will only execute the <C>Print</C> statement in the
second line. This will print the string <C>hello, world.</C> on the screen
followed by a newline character <C>\n</C> that causes the &GAP; prompt to
appear on the next line rather than immediately following the printed
characters.
<P/>
The function definition has the following syntax.
<P/>
<K>function</K><C>( <A>arguments</A> ) <A>statements</A></C> <K>end</K>
<P/>
A function definition starts with the keyword <K>function</K> followed by
the formal parameter list <A>arguments</A> enclosed in parenthesis
<C>( )</C>.
The formal parameter list may be empty as in the example. Several
parameters are separated by commas. Note that there must be <E>no</E>
semicolon behind the closing parenthesis. The function definition is
terminated by the keyword <K>end</K>.
<P/>
A &GAP; function is an expression like an integer, a sum or a list.
Therefore it may be assigned to a variable. The terminating semicolon
in the example does not belong to the function definition but
terminates the assignment of the function to the name <C>sayhello</C>.
Unlike in the case of integers, sums, and lists the value of the
function <C>sayhello</C> is echoed in the abbreviated fashion
<C>function( ) ... end</C>.
This shows the most interesting part of a function: its
formal parameter list (which is empty in this example). The complete
value of <C>sayhello</C> is returned if you use the function
<Ref Func="Print" BookName="ref"/>.
<P/>
<Example><![CDATA[
gap> Print(sayhello, "\n");
function ( )
Print( "hello, world.\n" );
return;
end
]]></Example>
<P/>
Note the additional newline character <C>"\n"</C> in the
<Ref Func="Print" BookName="ref"/>
statement. It is printed after the object <C>sayhello</C> to start a new
line. The extra <K>return</K> statement is inserted by &GAP; to simplify
the process of executing the function.
<P/>
The newly defined function <C>sayhello</C> is executed by calling <C>sayhello()</C>
with an empty argument list.
<P/>
<Example><![CDATA[
gap> sayhello();
hello, world.
]]></Example>
<P/>
However, this is not a typical example as no value is returned but only a
string is printed.
</Section>
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<Section Label="If Statements">
<Heading>If Statements</Heading>
In the following example we define a function <C>sign</C> which determines
the sign of an integer.
<P/>
<Example><![CDATA[
gap> sign:= function(n)
> if n < 0 then
> return -1;
> elif n = 0 then
> return 0;
> else
> return 1;
> fi;
> end;
function( n ) ... end
gap> sign(0); sign(-99); sign(11);
0
-1
1
]]></Example>
<P/>
This example also introduces the <K>if</K> statement which is used to execute
statements depending on a condition. The <K>if</K> statement has the
following syntax.
<P/>
<K>if</K> <A>condition</A> <K>then</K>
<A>statements</A>
<K>elif</K> <A>condition</A> <K>then</K>
<A>statements</A>
<K>else</K>
<A>statements</A>
<K>fi</K>
<P/>
There may be several <K>elif</K> parts. The <K>elif</K> part as well as the <K>else</K>
part of the <K>if</K> statement may be omitted. An <K>if</K> statement is no
expression and can therefore not be assigned to a variable. Furthermore
an <K>if</K> statement does not return a value.
<P/>
Fibonacci numbers are defined recursively by <M>f(1) = f(2) = 1</M> and
<M>f(n) = f(n-1) + f(n-2)</M> for <M>n \geq 3</M>.
Since functions in &GAP; may call themselves,
a function <C>fib</C> that computes Fibonacci numbers can be implemented
basically by typing the above equations. (Note however that this is a very
inefficient way to compute <M>f(n)</M>.)
<P/>
<Example><![CDATA[
gap> fib:= function(n)
> if n in [1, 2] then
> return 1;
> else
> return fib(n-1) + fib(n-2);
> fi;
> end;
function( n ) ... end
gap> fib(15);
610
]]></Example>
<P/>
There should be additional tests for the argument <C>n</C> being a positive
integer. This function <C>fib</C> might lead to strange results if called
with other arguments. Try inserting the necessary tests into this example.
</Section>
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<Section Label="Local Variables">
<Heading>Local Variables</Heading>
A function <C>gcd</C> that computes the greatest common divisor of two
integers by Euclid's algorithm will need a variable in addition to the
formal arguments.
<P/>
<Example><![CDATA[
gap> gcd:= function(a, b)
> local c;
> while b <> 0 do
> c:= b;
> b:= a mod b;
> a:= c;
> od;
> return c;
> end;
function( a, b ) ... end
gap> gcd(30, 63);
3
]]></Example>
<P/>
The additional variable <C>c</C> is declared as a <E>local</E> variable in the
<K>local</K> statement of the function definition. The <K>local</K> statement, if
present, must be the first statement of a function definition. When
several local variables are declared in only one <K>local</K> statement they
are separated by commas.
<P/>
The variable <C>c</C> is indeed a local variable, that is local to the
function <C>gcd</C>. If you try to use the value of <C>c</C> in the main loop you
will see that <C>c</C> has no assigned value unless you have already assigned
a value to the variable <C>c</C> in the main loop. In this case the local
nature of <C>c</C> in the function <C>gcd</C> prevents the value of the <C>c</C> in the
main loop from being overwritten.
<P/>
<Example><![CDATA[
gap> c:= 7;;
gap> gcd(30, 63);
3
gap> c;
7
]]></Example>
<P/>
We say that in a given scope an identifier identifies a unique variable.
A <E>scope</E> is a lexical part of a program text. There is the global scope
that encloses the entire program text, and there are local scopes that
range from the <K>function</K> keyword, denoting the beginning of a function
definition, to the corresponding <K>end</K> keyword. A local scope introduces
new variables, whose identifiers are given in the formal argument list
and the local declaration of the function. The usage of an identifier in
a program text refers to the variable in the innermost scope that has
this identifier as its name.
</Section>
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<Section Label="Recursion">
<Heading>Recursion</Heading>
We have already seen recursion in the function <C>fib</C>
in Section <Ref Sect="If Statements"/>.
Here is another, slightly more complicated example.
<P/>
We will now write a function to determine the number of partitions of
a positive integer. A partition of a positive integer is a descending
list of numbers whose sum is the given integer. For example
<M>[4,2,1,1]</M> is a partition of 8. Note that there is just one partition
of 0, namely <M>[ ]</M>. The complete set of all partitions of an integer
<M>n</M> may be divided into subsets with respect to the largest element.
The number of partitions of <M>n</M> therefore equals the sum of the
numbers of partitions of <M>n-i</M> with elements less than or equal to <M>i</M>
for all possible <M>i</M>. More generally the number of partitions of <M>n</M>
with elements less than <M>m</M> is the sum of the numbers of partitions of
<M>n-i</M> with elements less than <M>i</M> for <M>i</M> less than <M>m</M> and <M>n</M>. This
description yields the following function.
<P/>
<Example><![CDATA[
gap> nrparts:= function(n)
> local np;
> np:= function(n, m)
> local i, res;
> if n = 0 then
> return 1;
> fi;
> res:= 0;
> for i in [1..Minimum(n,m)] do
> res:= res + np(n-i, i);
> od;
> return res;
> end;
> return np(n,n);
> end;
function( n ) ... end
]]></Example>
<P/>
We wanted to write a function that takes one argument. We solved the
problem of determining the number of partitions in terms of a recursive
procedure with two arguments. So we had to write in fact two functions.
The function <C>nrparts</C> that can be used to compute the number of
partitions indeed takes only one argument. The function <C>np</C> takes two
arguments and solves the problem in the indicated way. The only task of
the function <C>nrparts</C> is to call <C>np</C> with two equal arguments.
<P/>
We made <C>np</C> local to <C>nrparts</C>. This illustrates the possibility of
having local functions in &GAP;. It is however not necessary to put
it there. <C>np</C> could as well be defined on the main level, but then
the identifier <C>np</C> would be bound and could not be used for other
purposes, and if it were used the essential function <C>np</C> would no
longer be available for <C>nrparts</C>.
<P/>
Now have a look at the function <C>np</C>. It has two local variables <C>res</C>
and <C>i</C>. The variable <C>res</C> is used to collect the sum and <C>i</C> is a
loop variable. In the loop the function <C>np</C> calls itself again with
other arguments. It would be very disturbing if this call of <C>np</C> was
to use the same <C>i</C> and <C>res</C> as the calling <C>np</C>. Since the new call
of <C>np</C> creates a new scope with new variables this is fortunately not
the case.
<P/>
Note that the formal parameters <A>n</A> and <A>m</A> of <C>np</C> are treated like
local variables.
<P/>
(Regardless of the recursive structure of an algorithm it is often
cheaper (in terms of computing time) to avoid a recursive
implementation if possible (and it is possible in this case), because
a function call is not very cheap.)
</Section>
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<Section Label="Further Information about Functions">
<Heading>Further Information about Functions</Heading>
The function syntax is described in Section <Ref Chap="Functions" BookName="ref"/>. The <K>if</K>
statement is described in more detail in Section <Ref Sect="If" BookName="ref"/>. More about
Fibonacci numbers is found in Section <Ref Func="Fibonacci" BookName="ref"/> and more about
partitions in Section <Ref Func="Partitions" BookName="ref"/>.
</Section>
</Chapter>
<!-- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -->
<!-- %% -->
<!-- %E -->
|