Welcome To Our Shell

Mister Spy & Souheyl Bypass Shell

Current Path : /usr/share/gap/doc/ref/

Linux ift1.ift-informatik.de 5.4.0-216-generic #236-Ubuntu SMP Fri Apr 11 19:53:21 UTC 2025 x86_64
Upload File :
Current File : //usr/share/gap/doc/ref/chap4.txt

  
  4 The Programming Language
  
  This  chapter describes the GAP programming language. It should allow you in
  principle  to  predict  the result of each and every input. In order to know
  what we are talking about, we first have to look more closely at the process
  of interpretation and the various representations of data involved.
  
  
  4.1 Language Overview
  
  First  we  have the input to GAP, given as a string of characters. How those
  characters  enter  GAP  is  operating  system dependent, e.g., they might be
  entered  at  a  terminal,  pasted with a mouse into a window, or read from a
  file.  The  mechanism does not matter. This representation of expressions by
  characters  is  called  the external representation of the expression. Every
  expression  has  at least one external representation that can be entered to
  get exactly this expression.
  
  The  input,  i.e.,  the external representation, is transformed in a process
  called  reading  to  an  internal representation. At this point the input is
  analyzed  and  inputs that are not legal external representations, according
  to  the  rules  given below, are rejected as errors. Those rules are usually
  called the syntax of a programming language.
  
  The   internal  representation  created  by  reading  is  called  either  an
  expression  or  a  statement.  Later  we  will distinguish between those two
  terms.  However  for now we will use them interchangeably. The exact form of
  the  internal  representation  does  not  matter.  It  could  be a string of
  characters  equal  to the external representation, in which case the reading
  would  only  need  to  check  for  errors.  It  could be a series of machine
  instructions  for  the  processor on which GAP is running, in which case the
  reading  would  more  appropriately  be  called compilation. It is in fact a
  tree-like structure.
  
  After  the  input  has been read it is again transformed in a process called
  evaluation  or  execution. Later we will distinguish between those two terms
  too,  but for the moment we will use them interchangeably. The name hints at
  the  nature of this process, it replaces an expression with the value of the
  expression.  This  works  recursively, i.e., to evaluate an expression first
  the  subexpressions  are  evaluated  and then the value of the expression is
  computed  from  those values according to rules given below. Those rules are
  usually called the semantics of a programming language.
  
  The result of the evaluation is, not surprisingly, called a value. Again the
  form  in which such a value is represented internally does not matter. It is
  in fact a tree-like structure again.
  
  The  last  process  is  called  printing. It takes the value produced by the
  evaluation  and  creates  an  external  representation,  i.e.,  a  string of
  characters  again.  What  you  do with this external representation is up to
  you.  You  can  look  at it, paste it with the mouse into another window, or
  write it to a file.
  
  Lets  look  at  an  example to make this more clear. Suppose you type in the
  following string of 8 characters
  
  
    1 + 2 * 3;
  
  
  GAP  takes  this  external  representation  and creates a tree-like internal
  representation, which we can picture as follows
  
  
      +
     / \
    1   *
       / \
      2   3
  
  
  This  expression is then evaluated. To do this GAP first evaluates the right
  subexpression  2*3. Again, to do this GAP first evaluates its subexpressions
  2  and  3.  However they are so simple that they are their own value, we say
  that  they  are  self-evaluating.  After  this has been done, the rule for *
  tells  us  that  the  value  is  the  product  of  the  values  of  the  two
  subexpressions,  which  in  this  case is clearly 6. Combining this with the
  value  of the left operand of the +, which is self-evaluating, too, gives us
  the  value  of the whole expression 7. This is then printed, i.e., converted
  into the external representation consisting of the single character 7.
  
  In  this  fashion  we can predict the result of every input when we know the
  syntactic  rules  that  govern the process of reading and the semantic rules
  that  tell us for every expression how its value is computed in terms of the
  values of the subexpressions. The syntactic rules are given in sections 4.2,
  4.3,  4.4,  4.5, and 4.6, the semantic rules are given in sections 4.7, 4.8,
  4.11,  4.12,  4.13,  4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.20, 4.23, and the
  chapters describing the individual data types.
  
  
  4.2 Lexical Structure
  
  Most input of GAP consists of sequences of the following characters.
  
  Digits, uppercase and lowercase letters, Space, Tab, Newline, Return and the
  special characters
  
  
    "    `    (    )    *    +    ,    -    #
    .    /    :    ;    <    =    >    ~    
    [    \    ]    ^    _    {    }    ! 
  
  
  It  is possible to use other characters in identifiers by escaping them with
  backslashes,  but  we  do  not recommend to use this feature. Inside strings
  (see  section 4.3  and chapter 27) and comments (see 4.4) the full character
  set supported by the computer is allowed.
  
  
  4.3 Symbols
  
  The  process of reading, i.e., of assembling the input into expressions, has
  a subprocess, called scanning, that assembles the characters into symbols. A
  symbol  is  a  sequence  of  characters that form a lexical unit. The set of
  symbols  consists  of keywords, identifiers, strings, integers, and operator
  and delimiter symbols.
  
  A  keyword  is  a  reserved  word  (see 4.5). An identifier is a sequence of
  letters, digits and underscores (or other characters escaped by backslashes)
  that  contains  at  least  one  non-digit and is not a keyword (see 4.6). An
  integer is a sequence of digits (see 14), possibly prepended by - and + sign
  characters.  A  string  is  a  sequence  of arbitrary characters enclosed in
  double quotes (see 27).
  
  Operator and delimiter symbols are
  
  
    +    -    *    /    ^    ~   !.
    =    <>   <    <=   >    >=  ![
    :=   .    ..   ->   ,    ;   !{
    [    ]    {    }    (    )    :
  
  
  Note also that during the process of scanning all whitespace is removed (see
  4.4).
  
  
  4.4 Whitespaces
  
  The  characters  Space,  Tab,  Newline,  and  Return  are  called whitespace
  characters.  Whitespace  is  used  as necessary to separate lexical symbols,
  such  as  integers,  identifiers,  or  keywords.  For example Thorondor is a
  single  identifier,  while  Th  or  ondor  is the keyword or between the two
  identifiers  Th and ondor. Whitespace may occur between any two symbols, but
  not  within  a  symbol.  Two  or  more  adjacent  whitespace  characters are
  equivalent  to  a  single  whitespace.  Apart  from the role as separator of
  symbols,  whitespace  characters  are  otherwise  insignificant.  Whitespace
  characters  may  also  occur  inside  a  string, where they are significant.
  Whitespace characters should also be used freely for improved readability.
  
  A  comment  starts  with the character #, which is sometimes called sharp or
  hatch,  and  continues to the end of the line on which the comment character
  appears. The whole comment, including # and the Newline character is treated
  as  a  single whitespace. Inside a string, the comment character # loses its
  role and is just an ordinary character.
  
  For example, the following statement
  
  
    if i<0 then a:=-i;else a:=i;fi;
  
  
  is equivalent to
  
  
    if i < 0 then   # if i is negative
      a := -i;      #   take its additive inverse
    else            # otherwise
      a := i;       #   take itself
    fi;
  
  
  (which  by the way shows that it is possible to write superfluous comments).
  However the first statement is not equivalent to
  
  
    ifi<0thena:=-i;elsea:=i;fi;
  
  
  since  the  keyword  if  must  be  separated  from  the  identifier  i  by a
  whitespace, and similarly then and a, and else and a must be separated.
  
  
  4.5 Keywords
  
  Keywords  are  reserved  words that are used to denote special operations or
  are  part  of  statements. They must not be used as identifiers. The list of
  keywords  is  contained  in  the  GAPInfo.Keywords  component of the GAPInfo
  record  (see  3.5-1).  We  will  show  how  to  print  it  in  a nice table,
  demonstrating at the same time some list manipulation techniques:
  
    Example  
    gap> keys:=SortedList( GAPInfo.Keywords );; l:=Length( keys );;
    gap> arr:= List( [ 0 .. Int( l/4 )-1 ], i-> keys{ 4*i + [ 1 .. 4 ] } );;
    gap> if l mod 4 <> 0 then Add( arr, keys{[ 4*Int(l/4) + 1 .. l ]} ); fi;
    gap> Length( keys ); PrintArray( arr );
    35
    [ [         Assert,           Info,        IsBound,           QUIT ],
      [  TryNextMethod,         Unbind,            and,         atomic ],
      [          break,       continue,             do,           elif ],
      [           else,            end,          false,             fi ],
      [            for,       function,             if,             in ],
      [          local,            mod,            not,             od ],
      [             or,           quit,       readonly,      readwrite ],
      [            rec,         repeat,         return,           then ],
      [           true,          until,          while ] ]
  
  
  Note  that  (almost) all keywords are written in lowercase and that they are
  case sensitive. For example else is a keyword; Else, eLsE, ELSE and so forth
  are  ordinary identifiers. Keywords must not contain whitespace, for example
  el if is not the same as elif.
  
  Note: Several tokens from the list of keywords above may appear to be normal
  identifiers  representing  functions  or  literals  of various kinds but are
  actually implemented as keywords for technical reasons. The only consequence
  of this is that those identifiers cannot be re-assigned, and do not actually
  have  function  objects  bound  to  them,  which  could be assigned to other
  variables  or  passed  to  functions. These keywords are true, false, Assert
  (7.5-3),  IsBound  (4.8-1),  Unbind  (4.8-2), Info (7.4-5) and TryNextMethod
  (78.4-1).
  
  Keywords  atomic,  readonly,  readwrite are not used at the moment. They are
  reserved  for  the  future version of GAP to prevent their accidental use as
  identifiers.
  
  
  4.6 Identifiers
  
  An  identifier  is  used  to  refer  to  a variable (see 4.8). An identifier
  usually consists of letters, digits, underscores _, and at-characters @, and
  must  contain  at  least  one  non-digit. An identifier is terminated by the
  first  character  not in this class. Note that the at-character @ is used to
  implement namespaces, see Section 4.10 for details.
  
  Examples of valid identifiers are
  
  
    a           foo         aLongIdentifier
    hello       Hello       HELLO
    x100        100x       _100
    some_people_prefer_underscores_to_separate_words
    WePreferMixedCaseToSeparateWords
    abc@def
  
  
  Note  that  case is significant, so the three identifiers in the second line
  are distinguished.
  
  The  backslash  \  can be used to include other characters in identifiers; a
  backslash  followed  by  a  character is equivalent to the character, except
  that  this  escape  sequence  is  considered  to  be an ordinary letter. For
  example
  
  
    G\(2\,5\)
  
  
  is an identifier, not a call to a function G.
  
  An  identifier  that  starts  with  a  backslash  is never a keyword, so for
  example \* and \mod are identifiers.
  
  The  length  of  identifiers  is  not  limited,  however only the first 1023
  characters  are significant. The escape sequence \newline is ignored, making
  it possible to split long identifiers over multiple lines.
  
  4.6-1 IsValidIdentifier
  
  IsValidIdentifier( str )  function
  
  returns  true  if the string str would form a valid identifier consisting of
  letters,  digits  and  underscores;  otherwise it returns false. It does not
  check whether str contains characters escaped by a backslash \.
  
  Note  that  the  at-character  is  used  to  implement namespaces for global
  variables in packages. See 4.10 for details.
  
  
  4.7 Expressions
  
  An expression is a construct that evaluates to a value. Syntactic constructs
  that  are  executed  to produce a side effect and return no value are called
  statements (see 4.14). Expressions appear as right hand sides of assignments
  (see  4.15),  as  actual  arguments  in  function  calls  (see 4.11), and in
  statements.
  
  Note that an expression is not the same as a value. For example 1 + 11 is an
  expression,  whose  value  is the integer 12. The external representation of
  this  integer is the character sequence 12, i.e., this sequence is output if
  the  integer  is printed. This sequence is another expression whose value is
  the integer 12. The process of finding the value of an expression is done by
  the interpreter and is called the evaluation of the expression.
  
  Variables, function calls, and integer, permutation, string, function, list,
  and  record  literals  (see  4.8,  4.11,  14, 42, 27, 4.23, 21, 29), are the
  simplest cases of expressions.
  
  Expressions,  for  example  the  simple  expressions mentioned above, can be
  combined  with  the  operators  to  form more complex expressions. Of course
  those  expressions  can  then be combined further with the operators to form
  even  more  complex  expressions. The operators fall into three classes. The
  comparisons  are  =,  <>,  <,  <=,  >,  >=,  and in (see 4.12 and 30.6). The
  arithmetic  operators  are  +,  -,  *, /, mod, and ^ (see 4.13). The logical
  operators are not, and, and or (see 20.4).
  
  The following example shows a very simple expression with value 4 and a more
  complex expression.
  
    Example  
    gap> 2 * 2;
    4
    gap> 2 * 2 + 9 = Fibonacci(7) and Fibonacci(13) in Primes;
    true
  
  
  For the precedence of operators, see 4.12.
  
  
  4.8 Variables
  
  A variable is a location in a GAP program that points to a value. We say the
  variable  is bound to this value. If a variable is evaluated it evaluates to
  this value.
  
  Initially  an  ordinary variable is not bound to any value. The variable can
  be  bound  to  a  value  by assigning this value to the variable (see 4.15).
  Because  of  this  we sometimes say that a variable that is not bound to any
  value  has  no assigned value. Assignment is in fact the only way by which a
  variable,  which  is not an argument of a function, can be bound to a value.
  After a variable has been bound to a value an assignment can also be used to
  bind the variable to another value.
  
  A  special  class  of variables is the class of arguments of functions. They
  behave  similarly  to other variables, except they are bound to the value of
  the actual arguments upon a function call (see 4.11).
  
  Each variable has a name that is also called its identifier. This is because
  in  a  given  scope  an identifier identifies a unique variable (see 4.6). A
  scope  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  function  keyword,  denoting the beginning of a function definition, to
  the corresponding end keyword. A local scope introduces new variables, whose
  identifiers  are given in the formal argument list and the local declaration
  of  the function (see 4.23). Usage of an identifier in a program text refers
  to the variable in the innermost scope that has this identifier as its name.
  Because  this mapping from identifiers to variables is done when the program
  is  read,  not when it is executed, GAP is said to have lexical scoping. The
  following  example shows how one identifier refers to different variables at
  different points in the program text.
  
  
    g := 0;      # global variable g
    x := function ( a, b, c )
      local  y;
      g := c;     # c refers to argument c of function x
      y := function ( y )
        local d, e, f;
        d := y;   # y refers to argument y of function y
        e := b;   # b refers to argument b of function x
        f := g;   # g refers to global variable g
        return d + e + f;
      end;
      return y( a ); # y refers to local y of function x
    end;
  
  
  It  is  important  to  note  that  the concept of a variable in GAP is quite
  different  from  the  concept  of  a  variable  in most compiled programming
  languages.
  
  In  those  languages  a variable denotes a block of memory. The value of the
  variable  is  stored  in this block. So in those languages two variables can
  have  the same value, but they can never have identical values, because they
  denote different blocks of memory. Note that some languages have the concept
  of  a  reference  argument. It seems as if such an argument and the variable
  used  in  the  actual  function call have the same value, since changing the
  argument's  value  also changes the value of the variable used in the actual
  function  call.  But  this  is  not so; the reference argument is actually a
  pointer  to  the  variable  used  in the actual function call, and it is the
  compiler  that  inserts enough magic to make the pointer invisible. In order
  for this to work the compiler needs enough information to compute the amount
  of  memory needed for each variable in a program, which is readily available
  in the declarations.
  
  In GAP on the other hand each variable just points to a value, and different
  variables can share the same value.
  
  4.8-1 IsBound
  
  IsBound( ident )  function
  
  IsBound  returns  true  if  the  variable ident points to a value, and false
  otherwise.
  
  For  records  and  lists  IsBound can be used to check whether components or
  entries, respectively, are bound (see Chapters 29 and 21).
  
  4.8-2 Unbind
  
  Unbind( ident )  function
  
  deletes  the identifier ident. If there is no other variable pointing to the
  same  value  as  ident  was,  this value will be removed by the next garbage
  collection.  Therefore  Unbind  can  be  used  to  get rid of unwanted large
  objects.
  
  For  records  and  lists Unbind can be used to delete components or entries,
  respectively (see Chapters 29 and 21).
  
  
  4.9 More About Global Variables
  
  The  vast  majority  of variables in GAP are defined at the outer level (the
  global  scope).  They are used to access functions and other objects created
  either in the GAP library or packages or in the user's code.
  
  Note  that  for  packages  there  is  a mechanism to implement package local
  namespaces on top of this global namespace. See Section 4.10 for details.
  
  Certain  special  facilities  are provided for manipulating global variables
  which are not available for other types of variable (such as local variables
  or function arguments).
  
  First,  such  variables  may  be  marked  read-only using MakeReadOnlyGlobal
  (4.9-2). In which case attempts to change them will fail. Most of the global
  variables  defined in the GAP library are so marked. read-only variables can
  be  made  read-write  again by calling MakeReadWriteGlobal (4.9-3). GAP also
  features constant variables, which are created by calling MakeConstantGlobal
  (4.9-4).  Constant  variables  can  never be changed. In some cases, GAP can
  optimise  code  which uses constant variables, as their value never changes.
  In  this  version  GAP  these  optimisations can be observed by printing the
  function back out, but this behaviour may change in future.
  
    Example  
    gap> globali := 1 + 2;;
    gap> globalb := true;;
    gap> MakeConstantGlobal("globali");
    gap> MakeConstantGlobal("globalb");
    gap> f := function()
    >     if globalb then
    >         return globali + 1;
    >     else
    >         return globali + 2;
    >     fi;
    > end;;
    gap> Print(f);
    function (  )
        return 3 + 1;
    end
  
  
  Second,  a  group  of  functions are supplied for accessing and altering the
  values assigned to global variables. Use of these functions differs from the
  use  of  assignment,  Unbind  (4.8-2) and IsBound (4.8-1) statements, in two
  ways.  First,  these functions always affect global variables, even if local
  variables  of the same names exist. Second, the variable names are passed as
  strings, rather than being written directly into the statements.
  
  Note  that  the  functions  NamesGVars  (4.9-9),  NamesSystemGVars (4.9-10),
  NamesUserGVars  (4.9-11),  and TemporaryGlobalVarName (4.9-12) deal with the
  global namespace.
  
  4.9-1 IsReadOnlyGlobal
  
  IsReadOnlyGlobal( name )  function
  
  returns  true  if  the global variable named by the string name is read-only
  and false otherwise (the default).
  
  4.9-2 MakeReadOnlyGlobal
  
  MakeReadOnlyGlobal( name )  function
  
  marks the global variable named by the string name as read-only.
  
  A  warning  is  given  if  name has no value bound to it or if it is already
  read-only.
  
  4.9-3 MakeReadWriteGlobal
  
  MakeReadWriteGlobal( name )  function
  
  marks the global variable named by the string name as read-write.
  
  A warning is given if name is already read-write.
  
    Example  
    gap> xx := 17;
    17
    gap> IsReadOnlyGlobal("xx");
    false
    gap> xx := 15;
    15
    gap> MakeReadOnlyGlobal("xx");
    gap> xx := 16;
    Variable: 'xx' is read only
    not in any function
    Entering break read-eval-print loop ...
    you can 'quit;' to quit to outer loop, or
    you can 'return;' after making it writable to continue
    brk> quit;
    gap> IsReadOnlyGlobal("xx");
    true
    gap> MakeReadWriteGlobal("xx");
    gap> xx := 16;
    16
    gap> IsReadOnlyGlobal("xx");
    false
  
  
  4.9-4 MakeConstantGlobal
  
  MakeConstantGlobal( name )  function
  
  MakeConstantGlobal  (  name  ) marks the global variable named by the string
  name  as  constant.  A  constant  variable  can  never  be  changed  or made
  read-write.  Constant  variables  can  only  take  an integer value, true or
  false. There is a limit on the size of allowed integers.
  
  A warning is given if name is already constant.
  
  4.9-5 ValueGlobal
  
  ValueGlobal( name )  function
  
  returns the value currently bound to the global variable named by the string
  name. An error is raised if no value is currently bound.
  
  4.9-6 IsBoundGlobal
  
  IsBoundGlobal( name )  function
  
  returns  true if a value currently bound to the global variable named by the
  string name and false otherwise.
  
  4.9-7 UnbindGlobal
  
  UnbindGlobal( name )  function
  
  removes any value currently bound to the global variable named by the string
  name. Nothing is returned.
  
  A  warning is given if name was not bound. The global variable named by name
  must be writable, otherwise an error is raised.
  
  4.9-8 BindGlobal
  
  BindGlobal( name, val )  function
  BindConstant( name, val )  function
  
  BindGlobal and BindConstant set the global variable named by the string name
  to  the  value val, provided that variable is writable. BindGlobal makes the
  resulting  variable read-only, while BindConstant makes it constant. If name
  already had a value, a warning message is printed.
  
  This  is  intended  to  be  the normal way to create and set official global
  variables (such as operations, filters and constants).
  
  Caution   should   be   exercised   in  using  these  functions,  especially
  UnbindGlobal  (4.9-7)  as unexpected changes in global variables can be very
  confusing for the user.
  
    Example  
    gap> xx := 16;
    16
    gap> IsReadOnlyGlobal("xx");
    false
    gap> ValueGlobal("xx");
    16
    gap> IsBoundGlobal("xx");
    true
    gap> BindGlobal("xx",17);
    #W BIND_GLOBAL: variable `xx' already has a value
    gap> xx;
    17
    gap> IsReadOnlyGlobal("xx");
    true
    gap> MakeReadWriteGlobal("xx");
    gap> Unbind(xx);
  
  
  4.9-9 NamesGVars
  
  NamesGVars(  )  function
  
  This function returns an immutable (see 12.6) sorted (see 21.19) list of all
  the  global  variable  names  known  to  the  system. This includes names of
  variables  which  were  bound but have now been unbound and some other names
  which  have  never been bound but have become known to the system by various
  routes.
  
  4.9-10 NamesSystemGVars
  
  NamesSystemGVars(  )  function
  
  This  function  returns  an immutable sorted list of all the global variable
  names created by the GAP library when GAP was started.
  
  4.9-11 NamesUserGVars
  
  NamesUserGVars(  )  function
  
  This  function returns an immutable sorted list of the global variable names
  created since the library was read, to which a value is currently bound.
  
  4.9-12 TemporaryGlobalVarName
  
  TemporaryGlobalVarName( [prefix] )  function
  
  returns  a  string that can be used as the name of a global variable that is
  not  bound  at  the time when TemporaryGlobalVarName is called. The optional
  argument  prefix  can  specify  a  string  with which the name of the global
  variable starts.
  
  
  4.10 Namespaces for GAP packages
  
  As  mentioned  in  Section  4.9  above  all  global variables share a common
  namespace.  This  can  relatively easily lead to name clashes, in particular
  when  many  GAP packages are loaded at the same time. To give package code a
  way   to   have   a   package  local  namespace  without  breaking  backward
  compatibility  of  the  GAP  language,  the  following  simple rule has been
  devised:
  
  If  in  package  code  a global variable that ends with an at-character @ is
  accessed  in  any  way, the name of the package is appended before accessing
  it.  Here,  package code refers to everything which is read with ReadPackage
  (76.3-1).  As  the  name  of  the  package  the  entry  PackageName  in  its
  PackageInfo.g  file  is  taken.  As  for  all identifiers, this name is case
  sensitive.
  
  For  example,  if  the  following is done in the code of a package with name
  xYz:
  
    Example  
    gap> a@ := 12;
    
  
  
  Then  actually the global variable a@xYz is assigned. Further accesses to a@
  within  the  package code will all be redirected to a@xYz. This includes all
  the  functions  described  in  Section  4.9  and  indeed  all  the functions
  described  Section  79.18  like  for example DeclareCategory (79.18-1). Note
  that  from  code in the same package it is still possible to access the same
  global variable via a@xYz explicitly.
  
  All  other  code  outside the package as well as interactive user input that
  wants to refer to that variable a@xYz must do so explicitly by using a@xYz.
  
  Since  in  earlier  releases  of  GAP  the  at-character  @  was not a legal
  character  (without using backslashes), this small extension of the language
  does not break any old code.
  
  
  4.11 Function Calls
  
  
  4.11-1 Function Call With Arguments
  
  function-var( [arg-expr[, arg-expr, ...]] )
  
  The  function  call has the effect of calling the function function-var. The
  precise semantics are as follows.
  
  First  GAP  evaluates  the function-var. Usually function-var is a variable,
  and  GAP  does  nothing  more  than taking the value of this variable. It is
  allowed  though  that  function-var  is a more complex expression, such as a
  reference to an element of a list (see Chapter 21) list-var[int-expr], or to
  a  component  of a record (see Chapter 29) record-var.ident. In any case GAP
  tests whether the value is a function. If it is not, GAP signals an error.
  
  Next  GAP  checks  that the number of actual arguments arg-exprs agrees with
  the  number of formal arguments as given in the function definition. If they
  do  not  agree  GAP  signals  an  error.  An  exception is the case when the
  function has a variable length argument list, which is denoted by adding ...
  after the final argument. In this case there must be at least as many actual
  arguments as there are formal arguments before the final argument and can be
  any larger number (see 4.23 for examples).
  
  Now  GAP  allocates for each formal argument and for each formal local (that
  is,  the identifiers in the local declaration) a new variable. Remember that
  a  variable  is a location in a GAP program that points to a value. Thus for
  each formal argument and for each formal local such a location is allocated.
  
  Next  the  arguments arg-exprs are evaluated, and the values are assigned to
  the newly created variables corresponding to the formal arguments. Of course
  the  first  value is assigned to the new variable corresponding to the first
  formal   argument,  the  second  value  is  assigned  to  the  new  variable
  corresponding  to  the  second formal argument, and so on. However, GAP does
  not make any guarantee about the order in which the arguments are evaluated.
  They might be evaluated left to right, right to left, or in any other order,
  but  each  argument is evaluated once. An exception again occurs if the last
  formal  argument has the name arg. In this case the values of all the actual
  arguments  not  assigned to the other formal parameters are stored in a list
  and  this  list  is assigned to the new variable corresponding to the formal
  argument arg.
  
  The new variables corresponding to the formal locals are initially not bound
  to  any  value.  So  trying to evaluate those variables before something has
  been assigned to them will signal an error.
  
  Now  the  body  of  the  function, which is a statement, is executed. If the
  identifier  of  one  of the formal arguments or formal locals appears in the
  body  of  the  function it refers to the new variable that was allocated for
  this  formal  argument  or  formal local, and evaluates to the value of this
  variable.
  
  If  during the execution of the body of the function a return statement with
  an  expression  (see  4.24) is executed, execution of the body is terminated
  and  the  value  of  the function call is the value of the expression of the
  return.  If  during  the execution of the body a return statement without an
  expression is executed, execution of the body is terminated and the function
  call  does  not produce a value, in which case we call this call a procedure
  call (see 4.16). If the execution of the body completes without execution of
  a  return statement, the function call again produces no value, and again we
  talk about a procedure call.
  
    Example  
    gap> Fibonacci( 11 );
    89
  
  
  The  above  example  shows  a  call  to the function Fibonacci (16.3-1) with
  actual  argument  11,  the  following  one  shows  a  call  to the operation
  RightCosets  (39.7-2)  where  the second actual argument is another function
  call.
  
    Example  
    gap> RightCosets( G, Intersection( U, V ) );;
  
  
  
  4.11-2 Function Call With Options
  
  function-var(  arg-expr[,  arg-expr,  ...][  :  [ option-expr [,option-expr,
  ....]]])
  
  As well as passing arguments to a function, providing the mathematical input
  to its calculation, it is sometimes useful to supply hints suggesting to GAP
  how  the  desired result may be computed more quickly, or specifying a level
  of tolerance for random errors in a Monte Carlo algorithm.
  
  Such  hints  may  be  supplied  to  a  function-call  and  to all subsidiary
  functions  called  from  that  call using the options mechanism. Options are
  separated  from  the  actual  arguments  by a colon : and have much the same
  syntax  as  the components of a record expression. The one exception to this
  is that a component name may appear without a value, in which case the value
  true is silently inserted.
  
  The following example shows a call to Size (30.4-6) passing the options hard
  (with the value true) and tcselection (with the string "external" as value).
  
    Example  
    gap> Size( fpgrp : hard, tcselection := "external" );
  
  
  Options  supplied  with function calls in this way are passed down using the
  global  options  stack  described  in  chapter  8, so that the call above is
  exactly equivalent to
  
    Example  
    gap> PushOptions( rec( hard := true, tcselection := "external") );
    gap> Size( fpgrp );
    gap> PopOptions( );
  
  
  Note  that any option may be passed with any function, whether or not it has
  any  actual  meaning  for  that  function, or any function called by it. The
  system provides no safeguard against misspelled option names.
  
  
  4.12 Comparisons
  
  left-expr = right-expr
  
  left-expr <> right-expr
  
  The  operator = tests for equality of its two operands and evaluates to true
  if  they  are equal and to false otherwise. Likewise <> tests for inequality
  of  its two operands. For each type of objects the definition of equality is
  given  in  the  respective chapter. Objects in different families (see 13.1)
  are  never  equal, i.e., = evaluates in this case to false, and <> evaluates
  to true.
  
  left-expr < right-expr
  
  left-expr > right-expr
  
  left-expr <= right-expr
  
  left-expr >= right-expr
  
  <  denotes  less than, <= less than or equal, > greater than, and >= greater
  than  or  equal of its two operands. For each kind of objects the definition
  of the ordering is given in the respective chapter.
  
  Note  that  <  implements a total ordering of objects (which can be used for
  example  to  sort  a  list  of elements). Therefore in general < will not be
  compatible  with  any inclusion relation (which can be tested using IsSubset
  (30.5-1)). (For example, it is possible to compare permutation groups with <
  in  a  total  ordering  of  all permutation groups, but this ordering is not
  compatible with the relation of being a subgroup.)
  
  Only  for  the  following  kinds of objects, an ordering via < of objects in
  different  families  (see 13.1) is supported. Rationals (see IsRat (17.2-1))
  are  smallest, next are cyclotomics (see IsCyclotomic (18.1-3)), followed by
  finite  field  elements  (see IsFFE  (59.1-1));  finite  field  elements  in
  different  characteristics  are compared via their characteristics, next are
  permutations  (see IsPerm  (42.1-1)),  followed  by the boolean values true,
  false,   and  fail  (see IsBool  (20.1-1)),  characters  (such  as  {}a{'}',
  see IsChar (27.1-1)), and lists (see IsList (21.1-1)) are largest; note that
  two  lists  can  be  compared with < if and only if their elements are again
  objects that can be compared with <.
  
  For  other  objects,  GAP does not provide an ordering via <. The reason for
  this  is  that a total ordering of all GAP objects would be hard to maintain
  when  new  kinds  of  objects  are  introduced, and such a total ordering is
  hardly used in its full generality.
  
  However,  for  objects  in  the filters listed above, the ordering via < has
  turned  out  to be useful. For example, one can form sorted lists containing
  integers  and  nested  lists  of  integers,  and  then  search in them using
  PositionSorted (see 21.16).
  
  Of course it would in principle be possible to define an ordering via < also
  for  certain  other  objects,  by  installing  appropriate  methods  for the
  operation  \<.  But  this may lead to problems at least as soon as one loads
  GAP  code  in  which  the  same  is  done,  under the assumption that one is
  completely  free to define an ordering via < for other objects than the ones
  for which the official GAP provides already an ordering via <.
  
  Comparison   operators,  including  the  operator  in  (see 21.8),  are  not
  associative,  Hence  it is not allowed to write a = b <> c = d, you must use
  (a  = b) <> (c = d) instead. The comparison operators have higher precedence
  than  the  logical  operators  (see 20.4),  but  lower  precedence  than the
  arithmetic  operators  (see 4.13).  Thus,  for  instance, a * b = c and d is
  interpreted as ((a * b) = c) and d).
  
  The  following  example  shows  a  comparison  where  the left operand is an
  expression.
  
    Example  
    gap> 2 * 2 + 9 = Fibonacci(7);
    true
  
  
  For the underlying operations of the operators introduced above, see 31.11.
  
  
  4.13 Arithmetic Operators
  
  + right-expr
  
  - right-expr
  
  left-expr + right-expr
  
  left-expr - right-expr
  
  left-expr * right-expr
  
  left-expr / right-expr
  
  left-expr mod right-expr
  
  left-expr ^ right-expr
  
  The  arithmetic  operators  are  +,  -,  *,  /,  mod,  and  ^.  The meanings
  (semantics) of those operators generally depend on the types of the operands
  involved, and they are defined in the various chapters describing the types.
  However basically the meanings are as follows.
  
  a + b denotes the addition of additive elements a and b.
  
  a - b denotes the addition of a and the additive inverse of b.
  
  a * b denotes the multiplication of multiplicative elements a and b.
  
  a / b denotes the multiplication of a with the multiplicative inverse of b.
  
  a  mod  b,  for  integer or rational left operand a and for non-zero integer
  right  operand b, is defined as follows. If a and b are both integers, a mod
  b  is the integer r in the integer range 0 .. |b| - 1 satisfying a = r + bq,
  for  some integer q (where the operations occurring have their usual meaning
  over the integers, of course).
  
  If a is a rational number and b is a non-zero integer, and a = m / n where m
  and n are coprime integers with n positive, then a mod b is the integer r in
  the  integer range 0 .. |b| - 1 such that m is congruent to rn modulo b, and
  r is called the modular remainder of a modulo b. Also, 1 / n mod b is called
  the modular inverse of n modulo b. (A pair of integers is said to be coprime
  (or relatively prime) if their greatest common divisor is 1.)
  
  With the above definition, 4 / 6 mod 32 equals 2 / 3 mod 32 and hence exists
  (and is equal to 22), despite the fact that 6 has no inverse modulo 32.
  
  Note: For rational a, a mod b could have been defined to be the non-negative
  rational  c  less  than |b| such that a - c is a multiple of b. However this
  definition is seldom useful and not the one chosen for GAP.
  
  +  and  -  can also be used as unary operations. The unary + is ignored. The
  unary - returns the additive inverse of its operand; over the integers it is
  equivalent to multiplication by -1.
  
  ^  denotes  powering  of a multiplicative element if the right operand is an
  integer, and is also used to denote the action of a group element on a point
  of a set if the right operand is a group element.
  
  The precedence of those operators is as follows. The powering operator ^ has
  the  highest  precedence, followed by the unary operators + and -, which are
  followed  by  the  multiplicative  operators *, /, and mod, and the additive
  binary  operators  +  and  - have the lowest precedence. That means that the
  expression  -2  ^  -2 * 3 + 1 is interpreted as (-(2 ^ (-2)) * 3) + 1. If in
  doubt use parentheses to clarify your intention.
  
  The  associativity  of  the  arithmetic  operators  is  as follows. ^ is not
  associative,  i.e., it is invalid to write 2^3^4, use parentheses to clarify
  whether  you  mean (2^3)^4 or 2^(3^4). The unary operators + and - are right
  associative,  because  they are written to the left of their operands. *, /,
  mod,  +,  and  -  are  all  left  associative, i.e., 1-2-3 is interpreted as
  (1-2)-3  not  as 1-(2-3). Again, if in doubt use parentheses to clarify your
  intentions.
  
  The   arithmetic  operators  have  higher  precedence  than  the  comparison
  operators  (see 4.12  and 30.6)  and the logical operators (see 20.4). Thus,
  for example, a * b = c and d is interpreted, ((a * b) = c) and d.
  
    Example  
    gap> 2 * 2 + 9;  # a very simple arithmetic expression
    13
  
  
  For  other  arithmetic  operations, and for the underlying operations of the
  operators introduced above, see 31.12.
  
  
  4.14 Statements
  
  Assignments  (see  4.15),  Procedure  calls  (see  4.16), if statements (see
  4.17), while (see 4.18), repeat (see 4.19) and for loops (see 4.20), and the
  return  statement  (see  4.24)  are  called  statements. They can be entered
  interactively  or  be part of a function definition. Every statement must be
  terminated by a semicolon.
  
  Statements,  unlike  expressions,  have  no value. They are executed only to
  produce  an  effect. For example an assignment has the effect of assigning a
  value  to  a  variable,  a  for loop has the effect of executing a statement
  sequence for all elements in a list and so on. We will talk about evaluation
  of   expressions  but  about  execution  of  statements  to  emphasize  this
  difference.
  
  Using expressions as statements is treated as syntax error.
  
    Example  
    gap> i := 7;;
    gap> if i <> 0 then k = 16/i; fi;
    Syntax error: := expected
    if i <> 0 then k = 16/i; fi;
                     ^
    gap> 
  
  
  As  you  can  see  from  the example this warning does in particular address
  those  users  who  are  used  to  languages  where  =  instead of := denotes
  assignment.
  
  Empty statements are permitted and have no effect.
  
  A  sequence of one or more statements is a statement sequence, and may occur
  everywhere  instead of a single statement. Each construct is terminated by a
  keyword. The simplest statement sequence is a single semicolon, which can be
  used  as an empty statement sequence. In fact an empty statement sequence as
  in  for  i  in [ 1 .. 2 ] do od is also permitted and is silently translated
  into the sequence containing just a semicolon.
  
  
  4.15 Assignments
  
  var := expr;
  
  The assignment has the effect of assigning the value of the expressions expr
  to the variable var.
  
  The  variable  var  may  be  an  ordinary variable (see 4.8), a list element
  selection  list-var[int-expr]  (see  21.4)  or  a record component selection
  record-var.ident  (see 29.3). Since a list element or a record component may
  itself  be  a  list  or  a record the left hand side of an assignment may be
  arbitrarily complex.
  
  Note  that  variables  do not have a type. Thus any value may be assigned to
  any variable. For example a variable with an integer value may be assigned a
  permutation or a list or anything else.
  
    Example  
    gap> data:= rec( numbers:= [ 1, 2, 3 ] );
    rec( numbers := [ 1, 2, 3 ] )
    gap> data.string:= "string";; data;
    rec( numbers := [ 1, 2, 3 ], string := "string" )
    gap> data.numbers[2]:= 4;; data;
    rec( numbers := [ 1, 4, 3 ], string := "string" )
  
  
  If  the  expression expr is a function call then this function must return a
  value. If the function does not return a value an error is signalled and you
  enter  a  break  loop  (see 6.4). As usual you can leave the break loop with
  quit;.  If  you  enter  return  return-expr;  the  value  of  the expression
  return-expr  is  assigned to the variable, and execution continues after the
  assignment.
  
    Example  
    gap> f1:= function( x ) Print( "value: ", x, "\n" ); end;;
    gap> f2:= function( x ) return f1( x ); end;;
    gap> f2( 4 );
    value: 4
    Function Calls: <func> must return a value at
    return f1( x );
     called from
    <function>( <arguments> ) called from read-eval-loop
    Entering break read-eval-print loop ...
    you can 'quit;' to quit to outer loop, or
    you can supply one by 'return <value>;' to continue
    brk> return "hello";
    "hello"
  
  
  In the above example, the function f2 calls f1 with argument 4, and since f1
  does  not  return  a  value  (but only prints a line value: ...), the return
  statement  of  f2  cannot  be  executed.  The  error message says that it is
  possible  to return an appropriate value, and the returned string "hello" is
  used by f2 instead of the missing return value of f1.
  
  
  4.16 Procedure Calls
  
  procedure-var( [arg-expr [,arg-expr, ...]] );
  
  The  procedure call has the effect of calling the procedure procedure-var. A
  procedure  call  is  done  exactly  like  a  function  call  (see 4.11). The
  distinction  between  functions  and  procedures is only for the sake of the
  discussion, GAP does not distinguish between them. So we state the following
  conventions.
  
  A  function  does  return  a  value but does not produce a side effect. As a
  convention  the  name  of  a  function is a noun, denoting what the function
  returns, e.g., "Length", "Concatenation" and "Order".
  
  A  procedure  is  a  function that does not return a value but produces some
  effect. Procedures are called only for this effect. As a convention the name
  of  a  procedure is a verb, denoting what the procedure does, e.g., "Print",
  "Append" and "Sort".
  
    Example  
    gap> Read( "myfile.g" );   # a call to the procedure Read
    gap> l := [ 1, 2 ];;
    gap> Append( l, [3,4,5] );  # a call to the procedure Append
  
  
  There  are a few exceptions of GAP functions that do both return a value and
  produce  some  effect. An example is Sortex (21.18-3) which sorts a list and
  returns the corresponding permutation of the entries.
  
  
  4.17 If
  
  if  bool-expr1  then  statements1 { elif bool-expr2 then statements2 }[ else
  statements3 ] fi;
  
  The  if statement allows one to execute statements depending on the value of
  some boolean expression. The execution is done as follows.
  
  First  the  expression  bool-expr1  following  the  if  is  evaluated. If it
  evaluates to true the statement sequence statements1 after the first then is
  executed, and the execution of the if statement is complete.
  
  Otherwise  the  expressions  bool-expr2  following the elif are evaluated in
  turn.  There  may be any number of elif parts, possibly none at all. As soon
  as  an  expression  evaluates  to  true the corresponding statement sequence
  statements2 is executed and execution of the if statement is complete.
  
  If the if expression and all, if any, elif expressions evaluate to false and
  there is an else part, which is optional, its statement sequence statements3
  is  executed  and the execution of the if statement is complete. If there is
  no  else  part  the if statement is complete without executing any statement
  sequence.
  
  Since  the if statement is terminated by the fi keyword there is no question
  where an else part belongs, i.e., GAP has no dangling else. In
  
  
    if expr1 then if expr2 then stats1 else stats2 fi; fi;
  
  
  the else part belongs to the second if statement, whereas in
  
  
    if expr1 then if expr2 then stats1 fi; else stats2 fi;
  
  
  the else part belongs to the first if statement.
  
  Since an if statement is not an expression it is not possible to write
  
  
    abs := if x > 0 then x; else -x; fi;
  
  
  which  would,  even  if legal syntax, be meaningless, since the if statement
  does not produce a value that could be assigned to abs.
  
  If  one of the expressions bool-expr1, bool-expr2 is evaluated and its value
  is  neither  true nor false an error is signalled and a break loop (see 6.4)
  is  entered.  As usual you can leave the break loop with quit;. If you enter
  return  true;,  execution of the if statement continues as if the expression
  whose evaluation failed had evaluated to true. Likewise, if you enter return
  false;,  execution  of the if statement continues as if the expression whose
  evaluation failed had evaluated to false.
  
    Example  
    gap> i := 10;;
    gap> if 0 < i then
    >    s := 1;
    >  elif i < 0 then
    >    s := -1;
    >  else
    >    s := 0;
    >  fi;
    gap> s;  # the sign of i
    1
  
  
  
  4.18 While
  
  while bool-expr do statements od;
  
  The  while  loop  executes  the  statement  sequence  statements  while  the
  condition bool-expr evaluates to true.
  
  First  bool-expr  is  evaluated.  If  it evaluates to false execution of the
  while loop terminates and the statement immediately following the while loop
  is  executed  next.  Otherwise  if  it  evaluates to true the statements are
  executed and the whole process begins again.
  
  The  difference  between the while loop and the repeat until loop (see 4.19)
  is  that the statements in the repeat until loop are executed at least once,
  while  the statements in the while loop are not executed at all if bool-expr
  is false at the first iteration.
  
  If  bool-expr does not evaluate to true or false an error is signalled and a
  break  loop (see 6.4) is entered. As usual you can leave the break loop with
  quit;.  If  you  enter  return  false;,  execution  continues  with the next
  statement  immediately  following the while loop. If you enter return true;,
  execution  continues  at  statements,  after  which  the  next evaluation of
  bool-expr may cause another error.
  
  The  following example shows a while loop that sums up the squares 1^2, 2^2,
  ... until the sum exceeds 200.
  
    Example  
    gap> i := 0;; s := 0;;
    gap> while s <= 200 do
    >    i := i + 1; s := s + i^2;
    >  od;
    gap> s;
    204
  
  
  A while loop may be left prematurely using break, see 4.21.
  
  
  4.19 Repeat
  
  repeat statements until bool-expr;
  
  The  repeat  loop  executes  the  statement  sequence  statements  until the
  condition bool-expr evaluates to true.
  
  First  statements are executed. Then bool-expr is evaluated. If it evaluates
  to  true  the repeat loop terminates and the statement immediately following
  the  repeat  loop  is  executed next. Otherwise if it evaluates to false the
  whole process begins again with the execution of the statements.
  
  The  difference  between the while loop (see 4.18) and the repeat until loop
  is  that the statements in the repeat until loop are executed at least once,
  while  the statements in the while loop are not executed at all if bool-expr
  is false at the first iteration.
  
  If  bool-expr does not evaluate to true or false an error is signalled and a
  break  loop (see 6.4) is entered. As usual you can leave the break loop with
  quit;.  If  you  enter  return  true;,  execution  continues  with  the next
  statement immediately following the repeat loop. If you enter return false;,
  execution  continues  at  statements,  after  which  the  next evaluation of
  bool-expr may cause another error.
  
  The  repeat  loop in the following example has the same purpose as the while
  loop  in  the  preceding example, namely to sum up the squares 1^2, 2^2, ...
  until the sum exceeds 200.
  
    Example  
    gap> i := 0;; s := 0;;
    gap> repeat
    >    i := i + 1; s := s + i^2;
    >  until s > 200;
    gap> s;
    204
  
  
  A repeat loop may be left prematurely using break, see 4.21.
  
  
  4.20 For
  
  for simple-var in list-expr do statements od;
  
  The for loop executes the statement sequence statements for every element of
  the list list-expr.
  
  The statement sequence statements is first executed with simple-var bound to
  the  first  element of the list list-expr, then with simple-var bound to the
  second element of list-expr and so on. simple-var must be a simple variable,
  it  must  not  be  a  list  element selection list-var[int-expr] or a record
  component selection record-var.ident.
  
  The  execution  of  the  for  loop  over a list is exactly equivalent to the
  following while loop.
  
  
    loop_list := list;
    loop_index := 1;
    while loop_index <= Length(loop_list) do
      variable := loop_list[loop_index];
      statements
      loop_index := loop_index + 1;
    od;
  
  
  with the exception that loop_list and loop_index are different variables for
  each for loop, i.e., these variables of different for loops do not interfere
  with each other.
  
  The list list-expr is very often a range (see 21.22).
  
  for variable in [from..to] do statements od;
  
  corresponds to the more common
  
  for variable from from to to do statements od;
  
  in other programming languages.
  
    Example  
    gap> s := 0;;
    gap> for i in [1..100] do
    >    s := s + i;
    > od;
    gap> s;
    5050
  
  
  Note  in  the following example how the modification of the list in the loop
  body causes the loop body also to be executed for the new values.
  
    Example  
    gap> l := [ 1, 2, 3, 4, 5, 6 ];;
    gap> for i in l do
    >    Print( i, " " );
    >    if i mod 2 = 0 then Add( l, 3 * i / 2 ); fi;
    > od; Print( "\n" );
    1 2 3 4 5 6 3 6 9 9 
    gap> l;
    [ 1, 2, 3, 4, 5, 6, 3, 6, 9, 9 ]
  
  
  Note  in  the  following  example that the modification of the variable that
  holds the list has no influence on the loop.
  
    Example  
    gap> l := [ 1, 2, 3, 4, 5, 6 ];;
    gap> for i in l do
    >    Print( i, " " );
    >    l := [];
    > od; Print( "\n" );
    1 2 3 4 5 6 
    gap> l;
    [  ]
  
  
  for variable in iterator do statements od;
  
  It  is  also possible to have a for-loop run over an iterator (see 30.8). In
  this case the for-loop is equivalent to
  
  
    while not IsDoneIterator(iterator) do
      variable := NextIterator(iterator)
      statements
    od;
  
  
  for variable in object do statements od;
  
  Finally, if an object object which is not a list or an iterator appears in a
  for-loop,   then   GAP   will   attempt   to   evaluate  the  function  call
  Iterator(object).  If  this is successful then the loop is taken to run over
  the iterator returned.
  
    Example  
    gap> g := Group((1,2,3,4,5),(1,2)(3,4)(5,6));
    Group([ (1,2,3,4,5), (1,2)(3,4)(5,6) ])
    gap> count := 0;; sumord := 0;;
    gap> for x in g do
    > count := count + 1; sumord := sumord + Order(x); od;
    gap> count;
    120
    gap> sumord;
    471
  
  
  The effect of
  
  for variable in domain do
  
  should thus normally be the same as
  
  for variable in AsList(domain) do
  
  but  may  use  much less storage, as the iterator may be more compact than a
  list of all the elements.
  
  See 30.8 for details about iterators.
  
  A  for  loop  may  be  left prematurely using break, see 4.21. This combines
  especially  well with a loop over an iterator, as a way of searching through
  a domain for an element with some useful property.
  
  
  4.21 Break
  
  break;
  
  The  statement  break;  causes  an  immediate  exit  from the innermost loop
  enclosing it.
  
    Example  
    gap> g := Group((1,2,3,4,5),(1,2)(3,4)(5,6));
    Group([ (1,2,3,4,5), (1,2)(3,4)(5,6) ])
    gap> for x in g do
    > if Order(x) = 3 then
    > break;
    > fi; od;
    gap> x;
    (1,5,2)(3,4,6)
  
  
  It is an error to use this statement other than inside a loop.
  
    Example  
    gap> break;
    Syntax error: 'break' statement not enclosed in a loop
  
  
  
  4.22 Continue
  
  continue;
  
  The  statement  continue;  causes  the  rest of the current iteration of the
  innermost loop enclosing it to be skipped.
  
    Example  
    gap> g := Group((1,2,3),(1,2));
    Group([ (1,2,3), (1,2) ])
    gap> for x in g do
    > if Order(x) = 3 then
    > continue;
    > fi; Print(x,"\n"); od;
    ()
    (2,3)
    (1,3)
    (1,2)
  
  
  It is an error to use this statement other than inside a loop.
  
    Example  
    gap> continue;
    Syntax error: 'continue' statement not enclosed in a loop
  
  
  
  4.23 Function
  
  function( [ arg-ident {, arg-ident} ] )
  
    [local loc-ident {, loc-ident} ; ]
  
    statements
  
  end
  
  A function is in fact a literal and not a statement. Such a function literal
  can  be  assigned  to a variable or to a list element or a record component.
  Later this function can be called as described in 4.11.
  
  The  following  is  an example of a function definition. It is a function to
  compute values of the Fibonacci sequence (see Fibonacci (16.3-1)).
  
    Example  
    gap> fib := function ( n )
    >     local f1, f2, f3, i;
    >     f1 := 1; f2 := 1;
    >     for i in [3..n] do
    >       f3 := f1 + f2;
    >       f1 := f2;
    >       f2 := f3;
    >     od;
    >     return f2;
    >   end;;
    gap> List( [1..10], fib );
    [ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]
  
  
  Because  for  each  of  the  formal  arguments arg-ident and for each of the
  formal  locals  loc-ident  a  new variable is allocated when the function is
  called  (see  4.11),  it  is  possible that a function calls itself. This is
  usually  called  recursion.  The  following  is  a  recursive  function that
  computes values of the Fibonacci sequence.
  
    Example  
    gap> fib := function ( n )
    >     if n < 3 then
    >       return 1;
    >     else
    >       return fib(n-1) + fib(n-2);
    >     fi;
    >   end;;
    gap> List( [1..10], fib );
    [ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ]
  
  
  Note  that the recursive version needs 2 * fib(n)-1 steps to compute fib(n),
  while  the  iterative  version  of  fib  needs  only n-2 steps. Both are not
  optimal  however,  the  library function Fibonacci (16.3-1) only needs about
  Log(n) steps.
  
  As  noted  in  Section 4.11,  the  case  where a function's last argument is
  followed  by ... is special. It provides a way of defining a function with a
  variable  number  of  arguments.  The  values  of  the  actual arguments are
  computed  and the first ones are assigned to the new variables corresponding
  to  the formal arguments before the last argument, if any. The values of all
  the  remaining  actual  arguments  are  stored  in  a  list and this list is
  assigned  to  the  new  variable corresponding to the final formal argument.
  There  are  two  typical  scenarios  for  wanting such a possibility: having
  optional arguments and having any number of arguments.
  
  The  following  example  shows  one way that the function Position (21.16-1)
  might be encoded and demonstrates the optional argument scenario.
  
    Example  
    gap> position := function ( list, obj, arg... )    
    >     local pos;
    >     if 0 = Length(arg) then
    >       pos := 0;
    >     else
    >       pos := arg[1];
    >     fi;
    >     repeat
    >       pos := pos + 1;
    >       if pos > Length(list) then
    >         return fail;
    >       fi;
    >     until list[pos] = obj;
    >     return pos;
    >    end;
    function( list, obj, arg... ) ... end
    gap> position([1, 4, 2], 4);
    2
    gap> position([1, 4, 2], 3);
    fail
    gap> position([1, 4, 2], 4, 2);
    fail
  
  
  The following example demonstrates the any number of arguments scenario.
  
    Example  
    gap> sum := function ( l... )
    >     local total, x;
    >     total := 0;
    >     for x in l do
    >       total := total + x;
    >     od;
    >     return total;
    >    end;
    function( l... ) ... end
    gap> sum(1, 2, 3);
    6
    gap> sum(1, 2, 3, 4);
    10
    gap> sum();
    0
  
  
  The  user  should  compare  the  above  with the GAP function Sum (21.20-26)
  which,  for  example,  may  take  a  list argument and optionally an initial
  element (which zero should the sum of an empty list return?).
  
  GAP  will  also special case a function with a single argument with the name
  arg as function with a variable length list of arguments, as if the user had
  written arg....
  
  Note    that    if    a    function    f    is   defined   as   above   then
  NumberArgumentsFunction(f)  returns  minus  the  number  of formal arguments
  (including the final argument) (see NumberArgumentsFunction (5.1-2)).
  
  Using  the  ...  notation  on a function f with only a single named argument
  tells  GAP  that  when it encounters f that it should form a list out of the
  arguments  of f. What if one wishes to do the opposite: tell GAP that a list
  should  be  unwrapped  and  passed  as  several arguments to a function. The
  function CallFuncList (5.2-1) is provided for this purpose.
  
  Also see Chapter 5.
  
  { arg-list } -> expr
  
  This is a shorthand for
  
  function ( arg-list ) return expr; end.
  
  arg-list is a (possibly empty) argument list. Any arguments list which would
  be  valid  for  a normal GAP function is also valid here (including variadic
  arguments).
  
  The following gives a couple of examples of a typical use of such a function
  
    Example  
    gap> Sum( List( [1..100], {x} -> x^2 ) );
    338350
    gap> list := [3, 5, 2, 1, 3];;
    gap> Sort(list, {x,y} -> x > y);
    gap> list;
    [ 5, 3, 3, 2, 1 ]
    gap> f := {x,y...} -> y;;
    gap> f(1,2,3,4);
    [ 2, 3, 4 ]
    gap> f := {} -> 2;
    function(  ) ... end
    gap> Print(f);
    function (  )
        return 2;
    end
    gap> f();
    2
  
  
  The { and } may be omitted for functions with one argument:
  
    Example  
    gap> Sum( List( [1..100], {x} -> x^2 ) );
    338350
    gap> Sum( List( [1..100], x -> x^2 ) );
    338350
  
  
  When  the definition of a function fun1 is evaluated inside another function
  fun2,  GAP  binds  all  the  identifiers  inside  the function fun1 that are
  identifiers of an argument or a local of fun2 to the corresponding variable.
  This  set  of  bindings is called the environment of the function fun1. When
  fun1  is  called,  its  body  is executed in this environment. The following
  implementation  of  a  simple stack uses this. Values can be pushed onto the
  stack and then later be popped off again. The interesting thing here is that
  the  functions push and pop in the record returned by Stack access the local
  variable  stack  of  Stack.  When  Stack  is  called, a new variable for the
  identifier  stack  is created. When the function definitions of push and pop
  are then evaluated (as part of the return statement) each reference to stack
  is  bound to this new variable. Note also that the two stacks A and B do not
  interfere, because each call of Stack creates a new variable for stack.
  
    Example  
    gap> Stack := function ()
    >     local  stack;
    >     stack := [];
    >     return rec(
    >       push := function ( value )
    >         Add( stack, value );
    >       end,
    >       pop := function ()
    >         local  value;
    >         value := stack[Length(stack)];
    >         Unbind( stack[Length(stack)] );
    >         return value;
    >       end
    >     );
    >  end;;
    gap> A := Stack();;
    gap> B := Stack();;
    gap> A.push( 1 ); A.push( 2 ); A.push( 3 );
    gap> B.push( 4 ); B.push( 5 ); B.push( 6 );
    gap> A.pop(); A.pop(); A.pop();
    3
    2
    1
    gap> B.pop(); B.pop(); B.pop();
    6
    5
    4
  
  
  This  feature  should be used rarely, since its implementation in GAP is not
  very efficient.
  
  
  4.24 Return (With or without Value)
  
  return;
  
  In  this  form  return terminates the call of the innermost function that is
  currently  executing,  and control returns to the calling function. An error
  is  signalled if no function is currently executing. No value is returned by
  the function.
  
  return expr;
  
  In  this  form  return terminates the call of the innermost function that is
  currently  executing,  and returns the value of the expression expr. Control
  returns  to  the  calling  function. An error is signalled if no function is
  currently executing.
  
  Both  statements  can also be used in break loops (see 6.4). return; has the
  effect  that  the computation continues where it was interrupted by an error
  or  the  user hitting Ctrl-C. return expr; can be used to continue execution
  after  an  error. What happens with the value expr depends on the particular
  error.
  
  For  examples  of  return  statements,  see  the  functions fib and Stack in
  Section 4.23.
  

bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped)
Email: contact@elmoujehidin.net bypass 1.0, Devloped By El Moujahidin (the source has been moved and devloped) Email: contact@elmoujehidin.net