File: function.xml

package info (click to toggle)
gap 4r7p5-2
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 29,272 kB
  • ctags: 7,129
  • sloc: ansic: 107,802; xml: 46,868; sh: 3,548; perl: 2,329; makefile: 740; python: 94; asm: 62; awk: 6
file content (317 lines) | stat: -rw-r--r-- 12,164 bytes parent folder | download | duplicates (5)
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&nbsp;<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 -->