Provided by: afnix_2.8.1-1_amd64 bug

NAME

       vol-1 - afnix programmer's guide

GETTING STARTED

       AFNIX is a multi-threaded functional engine with dynamic symbol bindings that supports the
       object oriented paradigm. The system features a state of the art runtime engine that  runs
       on both 32 and 64 bits platforms. The system specification offers a rich syntax that makes
       the  functional  programming  a  pleasant  activity.  When   the   interpreter   is   used
       interactively,  textis  entered on the command line and executed when a complete and valid
       syntactic object has been constructed. Alternatively, the interpreter can execute a source
       file  or  operates  with  an  input  stream.   AFNIX is a comprehensive set of application
       clients, modules and services. The original distribution  contains  the  core  interpreter
       with   additional  clients  like  the  compiler,  the  librarian  and  the  debugger.  The
       distribution contains also a rich set of  modules  that  are  dedicated  to  a  particular
       domain.  The  basic  modules  are  the  standard  i/o  module,  the  system module and the
       networking module. Above modules are services. A  service  is  another  extension  of  the
       engine that provides extra functionalities with help of several modules. This hierarchy is
       strictly enforced in the system design and provides a clear functional separation  between
       application  domain.  When  looking  for a particular feature, it is always a good idea to
       think in term of module or service functionality.  AFNIX operates with a set  of  keywords
       and  predicates.  The  engine  has  a native Unicode database. The set of standard objects
       provides support for integers, real numbers,  strings,  characters  and  boolean.  Various
       containers  like  list,  vector,  hash table, bitset, and graphs are also available in the
       core distribution. The syntax incorporates the concept of lambda expression with  explicit
       closure.  Symbol  scope  limitation  within  a lambda expression is a feature called gamma
       expression. Form like notation with an easy block declaration is  also  another  extension
       with  respect  to  other  system. The object model provides a single inheritance mechanism
       with dynamic symbol resolution. Special features include instance parenting, class binding
       instance inference and deference. Native class derivation and method override is also part
       of the object model with fixed  class  objects  and  forms.  The  engine  incorporates  an
       original  regular  expression  engine  with  group  matching,  exact  or partial match and
       substitution.  An  advanced  exception  engine  is  also  provided  with  native  run-time
       compatibility.   AFNIX  implements  a  true multi-threaded engine with an automatic object
       protection mechanism against concurrent access. A read  and  write  locking  system  which
       operates  with  the  thread  engine  is  also  built in the core system. The object memory
       management is automatic inside the core interpreter. Finally, the engine is written in C++
       and  provides  runtime  compatibility  with it. Such compatibility includes the ability to
       instantiate  C++  classes,  use  virtual  methods  and  raise  or  catch   exceptions.   A
       comprehensive  programming  interface has been designed to ease the integration of foreign
       libraries.

       First contact
       The fundamental syntactic object is a form. A form is parsed and immediately  executed  by
       the  interpreter.  A  form  is  generally  constructed  with  a function name and a set of
       arguments. The process of executing a form is called  the  evaluation.  The  next  example
       illustrates  one  of  the simplest form which is supported by the engine. This form simply
       displays the message hello world.

       Hello world
       At the interpreter prompt, a form is constructed with  the  special  object  println.  The
       unique argument is a string which is placed between double quotes.

       (axi) println "Hello World"
       Hello World

       The  interpreter  can be invoked to enter one or several forms interactively. The form can
       also be placed in a text file and the interpreted called to  execute  it.  The  alsis  the
       referred  extension  for  a  text  file,  but  it  can be anything. A simple session which
       executes the above file -- assuming the original  file  is  called  hello.als--  is  shown
       below.

       zsh> axi hello.als
       Hello World

       In  interactive  mode,  the  interpreter  waits  for  a  form. When a form is successfully
       constructed, it  is  then  immediately  executed  by  the  engine.  Upon  completion,  the
       interpreter  prompt  is  displayed  and  the  interpreter is ready to accept a new form. A
       session is terminated by typing ctrl-d. Another way to use  the  engine  is  to  call  the
       compiler  client  called  axc, and then invoke the interpreter with the compiled file. The
       interpreter assumes the .axcextension for compiled file and will automatically figure  out
       which file to execute when a file name is given without an extension.

       zsh> axc hello.als
       zsh> axi hello.axc
       Hello World
       zsh> axi hello
       Hello World

       The  order  of  search  is  determined  by  a special system called the file resolver. Its
       behavior is described in a special chapter of this manual.

       Interpreter command
       The interpreter can be invoked with several options, a file to execute  and  some  program
       arguments. The hoption prints the various interpreter options.

       zsh> axi -h
       usage: axi [options] [file] [arguments]
       [h]           print this help message
       [v]           print system version
       [m]           enable the start module
       [i   path]    add a resolver path
       [e   mode]    force the encoding mode
       [f assert]    enable assertion checks
       [f nopath]    do not set initial path
       [f noseed]    do not seed random engine
       [f   seed]    seed random engine

       The  voption  prints the interpreter version and operating system. The foption turns on or
       off some additional options like the assertion checking. The use of program  arguments  is
       illustrated  later  in  this chapter. The ioption adds a path to the interpreter resolver.
       Several ioptions can be specified. The order of search is determined by the option  order.
       As mentioned earlier, the use of the resolver combined with the librarianis described in a
       specific chapter. If the initial file name to execute contains a directory path, such path
       is  added  automatically  to  the  interpreter  resolver  path  unless the nopathoption is
       specified.

       Interactive line editing
       Line editing capabilities is provided when the interpreter is  used  interactively.  Error
       messages  are  displayed  in red if the terminal supports colors. Various accelerators are
       bound to the terminal as indicated in the table below.

       Binding     Description
       backspace   Erase the previous character
       delete      Erase at the cursor position
       insert      Toggle insert with in-place
       ctrl-a      Move to the beginning of the line
       ctrl-e      Move to the end of the line
       ctrl-u      Clear the input line
       ctrl-k      Clear from the cursor position
       ctrl-l      Refresh the line editing

       The arrow are also bound to their usual functions. Note that when  using  the  history,  a
       multi-line command editing access is provided by the interpreter.

       Binding   Description
       left      Move the cursor to the left
       right     Move the cursor to the right

       up        Move up in the history list
       down      Move down in the history list

       Command line arguments
       The  interpreter command line arguments are stored in a vector called argvwhich is part of
       the interpobject. A complete discussion about object and class is  covered  in  the  class
       object  chapter.  At this time, it is just necessary to note that a method is invoked by a
       name separated from the object symbol name with a semicolon. The example below illustrates
       the use of the vector argument.

       # argv.als
       # print the argument length and the first one
       println "argument length: " (interp:argv:length)
       println "first argument : " (interp:argv:get 0)
       zsh> axi argv.als hello world
       2
       hello

       Loading a source file
       The interpreter object provides also the loadmethod to load a file. The argument must be a
       valid file path or an exception is raised. The loadmethod returns nil. When  the  file  is
       loaded, the interpreter input, output and error streams are used. The load operation reads
       one form after another and executes them sequentially.

       # load the source file demo.als
       (axi) interp:load "demo.als"
       # load the compiled file demo.axc
       (axi) interp:load "demo.axc"
       # load whatever is found
       (axi) interp:load "demo"

       The loadmethod operates with the help of the interpreter resolver. By default  the  source
       file  extension  is  als.  If  the  file  has  been compiled, the axcextension can be used
       instead. This force the interpreter to load the compiled version. If you are not sure,  or
       do  not  care about which file is loaded, the extension can be omitted. Without extension,
       the compiled file is searched first. If it is not found the source file  is  searched  and
       loaded.

       The compiler
       The  client  axcis  the  cross compiler. It generates a binary file that can be run across
       several platforms. The hoption prints the compiler options.

       usage: axc [options] [files]
       [h]            print this help message
       [v]            print version information
       [i] path       add a path to the resolver
       [e  mode]      force the encoding mode

       One or several files can be specified on the command line. The  source  file  is  searched
       with  the  help  of  the  resolver.  The resolver ioption can be used to add a path to the
       resolver.

       Writing structure
       The structure of file is a succession of valid syntactic objects separated by blank  lines
       or  comments.  During  the  compilation or the execution process, each syntactic object is
       processed one after another in a single pass. Reserved keywords are an  integral  part  of
       the  writing systems. The association of symbols and literal constitutes a form. A form is
       the basic execution block in the writing system. When the form uses reserved  keyword,  it
       is customary to refer to it as a special form.

       Character set and comments
       The  writing system operates with the standard Unicode character set. Comments starts with
       the character #. All characters are consumed until the end of line. Comments can be placed
       anywhere in the source file. Comments entered during an interactive session are discarded.

       Native objects
       The  writing  system  operates  mostly  with objects. An object is created upon request or
       automatically by the engine when a native representation  is  required.  To  perform  this
       task,  several  native  objects,  namely  Booleanfor  boolean objects, Integer, Relatiffor
       integer numbers, Realfor floating-point number, Byte, Characterand Stringfor character  or
       string  manipulation  are  built  inside  the engine. Most of the time, a native object is
       built implicitly from its lexical representation, but an explicit representation can  also
       be used.

       const boolean  true
       const integer  1999
       const relatif  1234567890R
       const real     2000.0
       const string   "afnix"
       const char     'a'
       trans symbol   "hello world"
       trans symbol   2000

       The  constand transreserve keywords are used to declare a new symbol. A symbol is simply a
       binding between a name and an object. Almost  any  standard  characters  can  be  used  to
       declare  a symbol. The constreserved keyword creates a constant symboland returns the last
       evaluated object. As a consequence, nested  constconstructs  are  possible  like  trans  b
       (const  a  1).  The transreserved keyword declare a new transient symbol. When a symbol is
       marked transient, the object bound to the symbol can be changed while this is not possible
       with a constant symbol. Eventually, a symbol can be destroyed with the special form unref.
       It is worth to note that it is the symbol which is destroyed and not the object associated
       with it.

       Stop and resume parsing
       The  parsing  process  is  stopped in the presence of the â—€character (Unicode U+25C0). The
       parsing operation is resumed with the  â–¶character  (Unicode  U+25B6).  Such  mechanism  is
       useful  when  dealing with multi line statements. This mechanism is also a good example of
       Unicode based control characters.

       Forms
       An implicit form is a single line command. When a command is becoming complex, the use  of
       the  standard  form notation is more readable. The standard form uses the (and )characters
       to start and close a form. A form causes an evaluation. When a  form  is  evaluated,  each
       symbol  in  the  form  are  evaluated  to  their  corresponding  internal object. Then the
       interpreter treats the first object of the form as the object to execute and the  rest  is
       the  argument  list  for the calling object. The use of form inside a form is the standard
       way to perform recursive evaluation with complex expressions.

       const three (+ 1 2)

       This example defines a symbol which is initialized with the integer 3, that is the  result
       of  the  computation  (+  1  2). The example shows also that a Polish notation is used for
       arithmetic. If fact, +is a built-in operator which causes the arguments to be  summed  (if
       possible).  Evaluation can be nested as well as definition and assignation. When a form is
       evaluated, the result of the evaluation is made available to  the  calling  form.  If  the
       result is obtained at the top level, the result is discarded.

       const  b (trans a (+ 1 2))
       assert a 3
       assert b 3

       This  program  illustrates  the mechanic of the evaluation process. The evaluation is done
       recursively. The (+ 1 2)form is evaluated as 3 and the  result  transmitted  to  the  form
       (trans  a  3).  This  form not only creates the symbol aand binds to it the integer 3, but
       returns also 3 which is the result of the previous evaluation. Finally, the form (const  b
       3)is  evaluated,  that  is,  the  symbol bis created and the result discarded. Internally,
       things are a little more complex, but the idea remains the same. This program  illustrates
       also the usage of the assertkeyword.

       Lambda expression
       A  lambda  expressionis another name for a function. The term comes historically from Lisp
       to express the fact that a lambda expression is analog to the concept of expression  found
       in  the  lambda  calculus.  There are various ways to create a lambda expression. A lambda
       expression is created with the transreserved keyword. A lambda expression takes 0 or  more
       arguments  and  returns  an object. A lambda expression is also an object by itself When a
       lambda expression is called, the arguments are evaluated from left to right. The  function
       is  then  called  and  the  object  result  is transmitted to the calling form. The use of
       transvs constis explain  later.  To  illustrate  the  use  of  a  lambda  expression,  the
       computation of an integer factorial is described in the next example.

       # declare the factorial function
       trans fact (n) (
         if (== n 1) 1 (* n (fact (- n 1))))
       # compute factorial 5
       println "factorial 5 = " (fact 5)

       This  example  calls  for  several comments. First the transkeyword defines a new function
       object with one argument called n. The body of the function is defined with the  ifspecial
       form  and  can  be  easily  understood.  The  function is called in the next form when the
       printlnspecial form is executed. Note that here,  the  call  to  factproduces  an  integer
       object, which is converted automatically by the printlnkeyword.

       Block form
       The  notation  used in the factprogram is the standard form notation originating from Lisp
       and the Scheme dialect. There is also another notation called the block formnotation  with
       the  use  of the {and }characters. A block form is a syntactic notation where each form in
       the block form is executed sequentially. The form can be either an implicit or  a  regular
       form. The factprocedure can be rewritten with the block notation as illustrated below.

       # declare the factorial procedure
       trans fact (n) {
         if (== n 1) 1 (* n (fact (- n 1)))
       }
       # compute factorial 5
       println "factorial 5 = " (fact 5)

       Another  way  to  create  a lambda expression is via the lambdaspecial form. Recall that a
       lambda expression is an object. So when such object is created, it can  be  bounded  to  a
       symbol. The factorial example could be rewritten with an explicit lambda call.

       # declare the factorial procedure
       const fact (lambda (n) (
           if (== n 1) 1 (* n (fact (- n 1)))))
       # compute factorial 5
       println "factorial 5 = " (fact 5)

       Note  that  here, the symbol factis a constant symbol. The use of constis reserved for the
       creation of gamma expression.

       Gamma expression
       A lambda expression can somehow becomes very slow during the execution, since  the  symbol
       evaluation  is  done  within  a set of nested call to resolve the symbols. In other words,
       each recursive call to a function creates a new  symbol  set  which  is  linked  with  its
       parent. When the recursion is becoming deep, so is the path to traverse from the lower set
       to the top one. There is also another mechanism called gamma  expressionwhich  binds  only
       the  function  symbol  set  to the top level one. The rest remains the same. Using a gamma
       expression can speedup significantly the execution.

       # declare the factorial procedure
       const fact (n) (
         if (== n 1) 1 (* n (fact (- n 1))))
       # compute factorial 5
       println "factorial 5 = " (fact 5)

       We will come back later to the concept of  gamma  expression.  The  use  of  the  reserved
       keyword  constto  declare  a  gamma  expression  makes  now  sense.  Since  most  function
       definitions are constant with one  level,  it  was  a  design  choice  to  implement  this
       syntactic  sugar.  Note  that gammais a reserved keyword and can be used to create a gamma
       expression object. On the other hand, note that the gamma expression  mechanism  does  not
       work for instance method. We will illustrate this point later in this book.

       Lambda generation
       A  lambda  expression  can be used to generate another lambda expression. In other word, a
       function can generate a function, an that capability is an  essential  ingredient  of  the
       functional programmingparadigm. The interesting part with lambda expression is the concept
       of closed variables. In the next example, looking at the  lambda  expression  inside  gen,
       notice  that  the  argument to the gamma is xwhile nis marked in a form before the body of
       the gamma. This notation indicates that the gamma should retain the value of the  argument
       nwhen  the  closure  is created. In the literature, you might discover a similar mechanism
       referenced as a closure. A closure is simply a variable which is closed  under  a  certain
       context.  When  a variable is reference in a context without any definition, such variable
       is called a free variable. We will see later more programs with closures. Note that it  is
       the object created by the lambda or the gamma call which is called a closure.

       # a gamma which creates a lambda
       const gen (n) (
         lambda (x) (n) (+ x n))
       # create a function which add 2 to its argument
       const add-2 (gen 2)
       # call add-2 with an argument and check
       println "result = " (add-2 3)

       In  short, a lambda expression is a function with or without closed variables, which works
       with nested symbol sets also called namesets. A gamma expression is  a  function  with  or
       without  closed  variable  which is bounded to the top level nameset. The reserved keyword
       transbinds a lambda expression. The reserved keyword  constbinds  a  gamma  expression.  A
       gamma expression cannot be used as an instance method.

       Multiple arguments binding
       A lambda or gamma expression can be defined to work with extra arguments using the special
       argsbinding. During a lambda or gamma expression  execution,  the  special  symbol  argsis
       defined  with the extra arguments passed at the call. For example, a gamma expression with
       0 formal argument and 2 actual arguments has argsdefined as a cons cell.

       const proc-nilp (args) {
         trans result 0
         for (i) (args) (result:+= i)
         eval result
       }
       assert 3 (proc-nilp 1 2)
       assert 7 (proc-nilp 1 2 4)

       The symbol argscan also be defined with formal arguments. In that case, argsis defined  as
       a cons cell with the remaining actual arguments.

       # check with arguments
       const proc-args (a b args) {
         trans result (+ a b)
         for (i) (args) (result:+= i)
         eval result
       }
       assert 3 (proc-args 1 2)
       assert 7 (proc-args 1 2 4)

       It  is an error to specify formal arguments after args. Multiple argsformal definition are
       not allowed. The symbol argscan also be defined as a constant argument.

       # check with arguments
       const proc-args (a b (const args)) {
         trans result (+ a b)
         for (i) (args) (result:+= i)
         eval result
       }
       assert 7 (proc-args 1 2 4)

       Nameset and bindings
       A namesetis a container of bindings between a name and symbolic variable. We use the  term
       symbolic  variableto  denote  any  binding between a name and an object. There are various
       ways to express such bindings. The most common one is called a  symbol.  Another  type  of
       binding  is  an  argument. Despite the fact they are different, they share a set of common
       properties, like being settable. Another point to note is the nature of the nameset. As  a
       matter  of  fact,  there  is  various  type of namesets. The top level nameset is called a
       global setand is designed to handle a large number  of  symbols.  In  a  lambda  or  gamma
       expression,  the  nameset  is  called  a  local setand is designed to be fast with a small
       number of symbols. The moral of this little story is to think always in terms of namesets,
       no  matter how it is implemented. All namesets support the concept of parent binding. When
       a nameset is created (typically during the execution of a lambda expression), this nameset
       is  linked with its parent one. This means that a symbol look-up is done by traversing all
       nameset from the bottom to the top and stopping when one is found. In  term  of  notation,
       the  current  namesetis  referenced  with  the  special  symbol  '.'. The parent namesetis
       referenced with the special symbol '..'. The  top  level  namesetis  referenced  with  the
       symbol '...'.

       Symbol
       A  symbol is an object which defines a binding between a name and an object. When a symbol
       is evaluated, the evaluation process consists in returning the  associated  object.  There
       are  various  ways  to create or set a symbol, and the different reserved keywords account
       for the various nature of binding which has to be done depending on  the  current  nameset
       state.  One  of  the  symbol  property  is to be constor not. When a symbol is marked as a
       constant, it cannot be modified. Note here that it is the symbol which  is  constant,  not
       the object. A symbol can be created with the reserved keywords constor trans.

       Creating a nameset
       A  nameset is an object which can be constructed directly by using the object construction
       notation. Once the object is created, it can be bounded to a symbol.  Here  is  a  nameset
       called examplein the top level nameset.

       # create a new nameset called example
       const example (nameset .)
       # bind a symbol in this nameset
       const example:hello "hello"
       println example:hello

       Qualified name
       In  the  previous  example, a symbol is referenced in a given nameset by using a qualified
       namesuch like example:hello. A qualified name defines a path to access a symbol.  The  use
       of  a qualified name is a powerful notation to reference an object in reference to another
       object. For example, the qualified name .:hellorefers to the symbol  helloin  the  current
       nameset.  The  qualified name ...:hellorefers to the symbol helloin the top level nameset.
       There are other use for qualified names, like method call with an instance.

       Symbol binding
       The transreserved keyword has been shown in all previous  example.  The  reserved  keyword
       transcreates  or  set  a  symbol in the current nameset. For example, the form trans a 1is
       evaluated as follow. First, a symbol named ais searched in the current  nameset.  At  this
       stage,  two situations can occur. If the symbol is found, it is set with the corresponding
       value. If the symbol is not found, it is created in the current nameset and set.  The  use
       of  qualified  name is also permitted -- and encouraged -- with trans. The exact nature of
       the symbol binding with a  qualified  name  depends  on  the  partial  evaluation  of  the
       qualified  name.  For example, trans example:hello 1will set or create a symbol binding in
       reference to the exampleobject. If examplerefers to a nameset, the symbol is bound in this
       nameset.  If  exampleis a class, hellois bounded as a class symbol. In theory, there is no
       restriction to use transon any object. If the  object  does  not  have  a  symbol  binding
       capability,  an exception is raised. For example, if nis an integer object, the form trans
       n:i 1will fail. With 3 or 4 arguments, transdefines  automatically  a  lambda  expression.
       This notation is a syntactic sugar. The lambda expression is constructed from the argument
       list and bounded to the specified symbol. The rule used to set or define  the  symbol  are
       the same as described above.

       # create automatically a lambda expression
       trans min (x y) (if (< x y) x y)

       Constant binding
       The  constreserved  keyword is similar to trans, except that it creates a constant symbol.
       Once the symbol is created, it cannot be changed. This constant property is  hold  by  the
       symbol  itself. When trying to set a constant symbol, an exception is raised. The reserved
       keyword constworks also with qualified names. The rules described previously are the same.
       When  a  partial  evaluation  is  done, the partial object is called to perform a constant
       binding. If such capability does not exist, an exception is raised. With 3 or 4 arguments,
       constdefines automatically a gamma expression. Like transthe rule are the same except that
       the symbol is marked constant.

       # create automatically a gamma expression
       const max (x y) (if (> x y) x y)

       Symbol unreferencing
       The unrefreserved keyword removes a symbol reference in a given context. When the  context
       is  a  nameset,  the  object  associated  with  the  symbol  is  detached from the symbol,
       eventually destroyed with the symbol removed from the nameset.

       # create a symbol number
       const x 1
       # unreference it
       unref x

       Arguments
       An expression argument is similar to a symbol, except that it is used only  with  function
       argument.  The concept of binding between a name and an object is still the same, but with
       an argument, the object is not stored as part of  the  argument,  but  rather  at  another
       location  which  is  the  execution  stack. An argument can also be constant. On the other
       hand, a single argument can have multiple bindings. Such situation  is  found  during  the
       same  function  call  in  two different threads. An argument list is part of the lambda or
       gamma expression declaration. If the argument is defined as a constant argument a sub form
       notation  is  used  to  defined this matter. For example, the maxgamma expression is given
       below.

       # create a gamma expression with const argument
       const max (gamma ((const x) (const y)) (if (> x y) x y))

       A special symbols named argsis defined during a lambda or gamma expression evaluation with
       the  remaining  arguments  passed  at  the time the call is made. The symbol can be either
       nilor bound to a list of objects.

       const proc-args (a b) {
         trans result (+ a b)
         for (i) (args) (result:+= i)
         eval result
       }
       assert 3 (proc-args 1 2)
       assert 7 (proc-args 1 2 4)

       Special forms
       Special forms provides are reserved  keywords  which  are  most  of  the  time  imperative
       statement,  as  part  of  the  writing  system.  Special forms are an integral part of the
       writing system and interact directly with the interpreter. In most cases, a special  forms
       returns the last evaluated object. Most of the special forms are control flow statements.

       If special form
       The  ifreserved  keyword  takes  two or three arguments. The first argument is the boolean
       condition to check. If the condition evaluates to truethe second  argument  is  evaluated.
       The  form  return  the result of such evaluation. If the condition evaluates to false, the
       third argument is evaluated or nil is returned  if  it  does  not  exist.  An  interesting
       example  which  combines the ifreserved keyword and a deep recursion is the computation of
       the Fibonacci sequence.

       const fibo (gamma (n) (
           if (< n 2) n (+ (fibo (- n 1)) (fibo (- n 2))))

       While special form
       The whilereserved keyword  takes  2  or  3  arguments.  With  2  arguments,  the  loop  is
       constructed  with  a  condition  and  a  form.  With 3 arguments, the first argument is an
       initial condition that is executed only once. When an argument acts as a  loop  condition,
       the  condition  evaluate  to  a  boolean. The loop body is executed as long as the boolean
       condition is true. An interesting example related to integer arithmetic with  a  whileloop
       is the computation of the greatest common divisor or gcd.

       const gcd (u v) {
         while (!= v 0) {
           trans r (u:mod v)
           u:= v
           v:= r
         }
         eval u
       }

       Note  in this previous example the use of the symbol =. The qualified name u:=is in fact a
       method call. Here, the integer uis assigned with a value. In this case, the symbol is  not
       changed.  It  is  the  object  which  is  muted. In the presence of 3 arguments, the first
       argument is an initialization condition that is executed only once. In this  mode,  it  is
       important  to note that the loop introduce its own nameset. The loop condition can be used
       to initialize a local condition variable.

       while (trans valid (is:valid-p)) (valid) {
         # do something
         # adjust condition
         valid:= (and (is:valid-p) (something-else))
       }

       Do special form
       The doreserved keyword is similar to the  whilereserved  keyword,  except  that  the  loop
       condition is evaluated after the body execution. The syntax call is opposite to the while.
       The loop can accept either 2 or 3 arguments. With 2 arguments, the first argument  is  the
       loop  body and the second argument is the exit loop condition. With 3 arguments, the first
       argument is the initial condition that is executed only once.

       # count the number of digits in a string
       const number-of-digits (s) {
         const len (s:length)
         trans index 0
         trans count 0
         do {
           trans c (s:get index)
           if (c:digit-p) (count:++)
         } (< (index:++) len)
         eval count
       }

       Loop special form
       The loopreserved keyword is another form of loop. It take four arguments. The first is the
       initialize  form.  The  second  is  the exit condition. The third is the step form and the
       fourth is the form to  execute  at  each  loop  step.  Unlike  the  whileand  doloop,  the
       loopspecial form creates its own nameset, since the initialize condition generally creates
       new symbol for the loop only.

       # a simple loop from 0 to 10
       loop (trans i 0) (< i 10) (i:++) (println i)

       A loop can also be designed with a Counterobject. In this case, a counter is created  with
       an  initial  and  final count values. The counter step-pmethod can then be used to run the
       loop

       # a counter from 0 to 10
       trans cntr (Counter 10)
       # a simple loop from 1 to 10
       loop (cntr:step-p) (println cntr)

       In this example, the counter prints from 1 to 10 since the counter is designed to  operate
       from 0 to 9, and the printlnfunction is called after the step-ppredicate.

       Switch special form
       The  switchreserved  keyword  is  a  condition  selector. The first argument is the switch
       selector. The second argument is a list of various value  which  can  be  matched  by  the
       switch value. A special symbol called elsecan be used to match any value.

       # return the primary color in a rgb
       const get-primary-color (color value) (
         switch color (
           ("red"   (return (value:substr 0 2)))
           ("green" (return (value:substr 2 4)))
           ("blue"  (return (value:substr 4 6)))
         ))

       Return special form
       The  returnreserved  keyword  indicates  an exceptional condition in the flow of execution
       within a lambda or gamma expression. When a return is executed, the associated argument is
       returned  and  the  execution terminates. If returnis used at the top level, the result is
       simply discarded.

       # initialize a vector with a value
       const vector-init (length value) {
         # treat nil vector first
         if (<= length 0) return (Vector)
         trans result (Vector)
         do (result:add value) (> (length:--) 0)
       }

       Eval and protect
       The evalreserved keyword forces the  evaluation  of  the  object  argument.  The  reserved
       keyword  evalis  typically used in a function body to return a particular symbol value. It
       can also be used to force the evaluation of a protected object. In many cases, evalis more
       efficient than return. The protectreserved keyword constructs an object without evaluating
       it. Typically when used with a form, protectreturn the form itself. It can also be used to
       prevent  a  symbol  evaluation.  When  used  with  a  symbol,  the symbol object itself is
       returned.

       const add (protect (+ 1 2))
       (eval add)

       Note that in the preceding example that the evaluation will  return  a  lambda  expression
       which is evaluated immediately and which return the integer 3.

       Assert special form
       The  assertreserved  keyword  check  for  equality between the two arguments and abort the
       execution in case of failure. By default, the assertion checking is turn off, and  can  be
       activated  with  the  command  option  f  assert.  Needless  to say that assertis used for
       debugging purpose.

       assert true   (> 2 0)
       assert 0      (- 2 2)
       assert "true" (String true)

       Block special form
       The blockreserved keyword executes a form in a new local set. The local set  is  destroyed
       at  the  completion  of  the execution. The blockreserved keyword returns the value of the
       last evaluated form. Since a new local set is created, any  new  symbol  created  in  this
       nameset  is destroyed at the completion of the execution. In other word, the blockreserved
       keyword allows the creation of a local scope.

       trans a 1
       block {
         assert    a 1
         trans     a (+ 1 1)
         assert    a 2
         assert ..:a 1
       }
       assert 1 a

       Built-in objects
       Several built-in objects and built-in operators for arithmetic and logical operations  are
       also  integrated  in  the writing system. The Integerand Realclasses are primarily used to
       manipulate numbers. The Booleanclass is used to for  boolean  operations.  Other  built-in
       objects  include Characterand String. The exact usage of these objects is described in the
       next chapter.

       Arithmetic operations
       Support for the arithmetic operations is provided with  the  standard  operator  notation.
       Normally,  these operators will tolerate various object type mixing and the returned value
       will generally be bound to an object that provides the minimum loss of  information.  Most
       of the operations are done with the +, -, *and /operators.

       (+ 1 2)
       (- 1)
       (* 3 5.0)
       (/ 4.0 2)

       Logical operations
       The  Booleanclass  is  used  to  represent the boolean value trueand false. These last two
       symbols are built-in in the interpreter as constant symbols. There are also special  forms
       like not, andand or. Their usage is self understandable.

       not true
       and true (== 1 0)
       or (< -1 0) (> 1 0)

       Predicates
       A  predicateis  a  function  which  returns  a  boolean object. There is always a built-in
       predicate associated with a built-in object. By convention, a  predicate  terminates  with
       the  sequence  -p.  The  nil-ppredicate  is  a special predicate which returns true if the
       object is nil. The object-ppredicate is the negation of the nil-ppredicate.

       Predicate     Description
       nil-p         check nil object
       eval-p        check evaluation
       real-p        check real object
       regex-p       check regex object
       object-p      check for non nil object

       string-p      check string object
       number-p      check number object
       method-p      check method object
       boolean-p     check boolean object
       integer-p     check integer object
       character-p   check character object

       For example, one can write a function which returns trueif the argument is a number,  that
       is, an integer or a real number.

       # return true if the argument is a number
       const number-p (n) (
         or (integer-p n) (real-p n))

       Special  predicates  for  functional  and  symbolic  programming  are also built-in in the
       engine.

       Predicate     Description
       class-p       check class object
       thread-p      check thread object
       promise-p     check promise object
       lexical-p     check lexical object
       literal-p     check literal object
       closure-p     check closure object
       nameset-p     check nameset object
       instance-p    check instance object
       qualified-p   check qualified object

       Finally, for each object, a predicate  is  also  associated.  For  example,  cons-pis  the
       predicate  for  the  Consobject and vector-pis the predicate for the Vectorobject. Another
       issue related to evaluation, is to decide whether or not an object can be  evaluated.  The
       predicate  eval-pwhich is a special form is designed to answer this question. Furthermore,
       the eval-ppredicate is useful to decide whether or  not  a  symbol  is  defined  or  if  a
       qualified name can be evaluated.

       assert true  (eval-p .)
       assert false (eval-p an-unknown-symbol)

       Class and instance
       Classes  and  instances  are  the  fundamental objects that provide support for the object
       oriented paradigm. A classis  a  nameset  which  can  be  bounded  automatically  when  an
       instanceof  that  class  is created. The class model is sloppy. Compared to other systems,
       there is no need to declare the data members for a  particular  class.  Data  members  are
       created  during  the  instance  construction.  An instance can also be created without any
       reference to a class. Methods can be bound to the  class  or  the  instance  or  both.  An
       instance can also be muted during the execution process.

       Class and members
       A  class  is  declared  with  the reserved keyword class. The resulting object acts like a
       nameset and it is possible to bind symbol to it.

       # create a class object
       const Circle (class)
       const Circle:PI 3.1415926535
       # access by qualified name
       println Circle:PI

       In the previous example, the symbol Circleis created as a class object. With the help of a
       qualified name, the symbol PIis created inside the class nameset. In this case, the symbol
       PIis invariant with respect to the instance object. A form can also be bound to the  class
       nameset.  In  both  cases, the symbol or the form is accessed with the help of a qualified
       name.

       Instances
       An instance of a class is created like any built-in object. If a  method  called  presetis
       defined for that class, the method is used to initialize the instance.

       # create a class
       const Circle (class)
       trans Circle:preset (r) {
         const this:radius (r:clone)
       }
       # create a radius 1 circle
       const c (Circle 1)

       This example calls for several comments. First the presetlambda expression is bound to the
       class. Since presetis a reserved name for the class  object,  the  form  is  automatically
       executed at the instance construction. Second, note that the instance data member radiusis
       created by the lambda expression and  another  reserved  keyword  called  thisis  used  to
       reference the instance object as it is customary with other programming systems.

       Instance method
       When a lambda expression is bound to the class or the instance, that lambda can be invoked
       as an instance method. When an instance method is invoked, the instance nameset is set  as
       the  parent nameset for that lambda. This is the main reason why a gamma expression cannot
       be used as an instance method. Therefore, the use  of  the  reserved  keyword  thisis  not
       recommended  in a gamma expression, although it is perfectly acceptable to create a symbol
       with such name.

       # create a perimeter method
       trans Circle:perimeter nil (
         * (* 2.0 Circle:PI) this:radius)
       # call the method with our circle
       trans p (c:perimeter)

       It must be clear that the perimetersymbol defines a method  at  the  class  level.  It  is
       perfectly  acceptable  to  define a methods at the instance level. Such method is called a
       specialized method.

       Miscellaneous features

       Iteration
       An iteration facility is provided for some objects known as iterable  objects.  The  Cons,
       Listand  Vectorare  typical  iterable  objects.  There  are two ways to iterate with these
       objects. The first method uses the forreserved keyword. The second method uses an explicit
       iterator which can be constructed by the object.

       # compute the scalar product of two vectors
       const scalar-product (u v) {
         trans result 0
         for (x y) (u v) (result:+= (* x y))
         eval result
       }

       The forreserved keyword iterate on both object uand v. For each iteration, the symbol xand
       yare set with their respective object value. In the example above, the result is  obtained
       by summing all intermediate products.

       # test the scalar product function
       const v1 (Vector 1 2 3)
       const v2 (Vector 2 4 6)
       (scalar-product v1 v2)

       The  iteration  can  be  done  explicitly  by  creating  an  iterator for each vectors and
       advancing steps by steps.

       # scalar product with explicit iterators
       const scalar-product (u v) {
         trans result 0
         trans u-it   (u:get-iterator)
         trans v-it   (v:get-iterator)
         while (u:valid-p) {
           trans x (u:get-object)
           trans y (v:get-object)
           result:+= (* x y)
           u:next
           v:next
         }
         eval result
       }

       In the example above, two iterators are constructed for both vectors uand v. The iteration
       is  done in a whileloop by invoking the valid-ppredicate. The get-objectmethod returns the
       object value at the current iterator position.

       Exception
       An exceptionis an unexpected change in the execution flow. The exception model is based on
       a  mechanism  which  throws the exception to be caught by a handler. The mechanism is also
       designed to be compatible with the native implementation. An exception is thrown with  the
       special  form  throw.  When  an  exception  is  thrown,  the  normal  flow of execution is
       interrupted and an object used  to  carry  the  exception  information  is  created.  Such
       exception object is propagated backward in the call stack until an exception handler catch
       it.The special form tryexecutes a form and catch an exception if one has been thrown. With
       one  argument,  the  form  is  executed and the result is the result of the form execution
       unless an exception is caught. If an exception is caught,  the  result  is  the  exception
       object. If the exception is a native one, the result is nil.

       try (+ 1 2)
       try (throw)
       try (throw "hello")
       try (throw "hello" "world")
       try (throw "hello" "world" "folks")

       The  exception  mechanism  is also designed to install an exception handler and eventually
       retrieve some information from the exception object. The reserved symbol whatcan  be  used
       to retrieve some exception information.

       # protected factorial
       const fact (n) {
         if (not (integer-p n))
         (throw "number-error" "invalid argument")
         if (== n 0) 1 (* n (fact (- n 1)))
       }
       # exception handler
       const handler nil {
         errorln what:eid ',' what:reason
       }
       (try (fact 5)       handler)
       (try (fact "hello") handler)

       The special symbol whatstores the necessary information about the place that generated the
       exception. Most of the time, the qualified name what:reasonor what:aboutis  used.The  only
       difference  is  that  what:aboutcontains the file name and line number associated with the
       reason that generated the exception.

       Regular Expressions
       A regular expression or regexis an object which is used to match  certain  text  patterns.
       Regular  expressions  are  built  implicitly  by  the  parser  with  the  use  of the [and
       ]characters. Special class of characters are defined with the help of the $character.  For
       example,  $dis  the  class  of  character  digits  as  defined  by the Unicode consortium.
       Different regular expression can be grouped by region to be matched as  indicated  in  the
       example below.

       if (== (const re [($d$d):($d$d)]) "12:31") {
         trans hr (re:get 0)
         trans mn (re:get 1)
       }

       In  the  previous  example,  a  regular  expression  object is bound to the symbol re. The
       regexcontains two groups. The call to the operator ==returns trueif the regex matches  the
       argument string. The getmethod can be used to retrieve the group by index.

       Delayed evaluation
       The  special  form delaycreates a special object called a promisewhich records the form to
       be later evaluated. The special form forcecauses a promise  to  be  evaluated.  Subsequent
       call with forcewill produce the same result.

       trans   y 3
       const   l ((lambda (x) (+ x y)) 1)
       assert  4 (force l)
       trans   y 0
       assert  4 (force l)

       Threads
       The  interpreter  provides  a  powerful mechanism which allows the concurrent execution of
       forms and the synchronization of shared objects. The engine provides supports the creation
       and  the  synchronization  of  threads  with a native object locking mechanism. During the
       execution, the interpreter wait until all threads are completed. A threads is created with
       the  reserved  keyword launch. In the presence of several threads, the interpreter manages
       automatically the shared objects and protect them against concurrent access.

       # shared variable access
       const var 0
       const decr nil (while true (var:= (- var 1)))
       const incr nil (while true (var:= (+ var 1)))
       const prtv nil (while true (println "value = " var))
       # start 3 threads
       launch (prtv)
       launch (decr)
       launch (incr)

       Form synchronization
       Although, the engine provides  an  automatic  synchronization  mechanism  for  reading  or
       writing  an  object,  it  is  sometimes necessary to control the execution flow. There are
       basically two techniques to do so. First, protect a form from being  executed  by  several
       threads.  Second,  wait  for one or several threads to complete their task before going to
       the next execution step. The reserved keyword synccan be used to synchronize a form.  When
       a  form,  is  synchronized,  the  engine guarantees that only one thread will execute this
       form.

       const print-message (code mesg) (
         sync {
           errorln "error  : " code
           errorln "message: " mesg
         }
       )

       The previous example create a gamma expression which make sure that both  the  error  code
       and error message are printed in one group, when several threads call it.

       Thread completion
       The  other  piece  of  synchronization  is  the  thread  completion  indicator. The thread
       descriptor contains a method called waitwhich suspend the calling thread until the  thread
       attached  to  the  descriptor  has been completed. If the thread is already completed, the
       method returns immediately.

       # simple flag
       const flag false
       # simple shared tester
       const ftest (bval) (flag:= bval)
       # run the thread and wait
       const thr (launch (ftest true))
       thr:wait
       assert true flag

       This example is taken from the test suites. It checks that a boolean variable is set in  a
       thread.  Note  the  use  of  the  waitmethod  to make sure the thread has completed before
       checking for the flag value. It is also worth to note that waitis one of the method  which
       guarantees that a thread result is valid. Another use of the waitmethod can be made with a
       vector of thread descriptors when one wants to wait until all of them have completed.

       # shared vector of threads descriptors
       const thr-group (Vector)
       # wait until all threads in the group are finished
       const wait-all nil (for (thr) (thr-group) (thr:wait))

       Condition variable
       A condition variableis another mechanism  to  synchronize  several  threads.  A  condition
       variable  is  modeled  with  the Condvarobject. At construction, the condition variable is
       initialized to false. A thread calling the  waitmethod  will  block  until  the  condition
       becomes  true.  The  markmethod can be used by a thread to change the state of a condition
       variable and eventually awake some threads which are blocked on it. The use  of  condition
       variable  is  particularly  recommended when one need to make sure a particular thread has
       been doing a particular task.

       The interpreter object
       The interpreter can also be seen as an  object.  As  such,  it  provides  several  special
       symbols  and  forms.  For  example,  the  symbol  argvis  the  argument vector. The symbol
       libraryis an interpreter method that loads  a  library.  A  complete  description  of  the
       interpreter object is made in a special chapter of this book.

LITERALS

       This  chapters  covers  in  detail  the  literals  objects  used to manipulate numbers and
       strings. First the integer, relatif and real numbers are described. There is a broad range
       of  methods  for these three objects that support numerical computation. As a second step,
       string and character objects are described. Many  examples  show  the  various  operations
       which  can  be  used  as  automatic  conversion between one type and another. Finally, the
       boolean object is described. These objects belongs to the class of literal objects,  which
       are  objects  that have a string representation. A special literal object known as regular
       expressionor regexis also described at the end of this chapter.

       Integer number
       The fundamental number representation is the Integer. The integer is a 64 bits signed  2's
       complement number. Even when running with a 32 bits machine, the 64 bits representation is
       used. If a larger representation is needed, the Relatifobject might be  more  appropriate.
       The Integerobject is a literal object that belongs to the number class.

       Integer format
       The default literal format for an integer is the decimal notation. The minus sign (without
       blank) indicates a negative number. Hexadecimal and binary notations can also be used with
       prefix 0xand 0b. The underscore character can be used to make the notation more readable.

       const a  123
       trans b -255
       const h  0xff
       const b  0b1111_1111

       Integer  number  are constructed from the literal notation or by using an explicit integer
       instance. The Integerclass offers standard constructors. The default  constructor  creates
       an integer object and initialize it to 0. The other constructors take either an integer, a
       real number, a character or a string.

       const a (Integer)
       const b (Integer 2000)
       const c (Integer "23")

       When the hexadecimal or binary notation is used, care should be taken to avoid a  negative
       integer.  For  example, 0x_8000_0000_0000_0000is the smallest negative number. This number
       exhibits also the strange property to be equal to its negation since with 2's  complement,
       there is no positive representation.

       Integer arithmetic
       Standard  arithmetic  operators are available as built-in operators. The usual addition +,
       multiplication *and division /operate with two arguments. The subtraction  -operates  with
       one or two arguments.

       + 3 4
       - 3 4
       - 3
       * 3 4
       / 4 2

       As  a  built-in  object,  the Integerobject offers various methods for built-in arithmetic
       which directly operates on the object. The following example illustrates these methods.

       trans i 0
       i:++
       i:--
       i:+ 4
       i:= 4
       i:- 1
       i:* 2
       i:/ 2
       i:+= 1
       i:-= 1
       i:*= 2
       i:/= 2

       As a side effect, these methods allows a const symbol to be modified.  Since  the  methods
       operates on an object, they do not modify the state of the symbol. Such methods are called
       mutable methods.

       const i 0
       i:= 1

       Integer comparison
       The comparison operators works the same. The only difference is that they always return  a
       Booleanresult.  The  comparison  operators are namely equal ==, not equal !=, less than <,
       less equal <=, greater >and greater equal >=. These operators take two arguments.

       == 0 1
       != 0 1

       Like the arithmetic methods, the comparison operators are  supported  as  object  methods.
       These methods return a Booleanobject.

       i:=  1
       i:== 1
       i:!= 0

       Integer calculus
       Armed with all these functions, it is possible to develop a battery of functions operating
       with numbers. As another example, we revisit the Fibonacci sequence as demonstrated in the
       introduction  chapter.  Such  example  was terribly slow, because of the double recursion.
       Another method suggested by Springer and Friedman uses two functions to perform  the  same
       job.

       const fib-it (gamma (n acc1 acc2) (
           if (== n 1) acc2 (fib-it (- n 1) acc2 (+ acc1 acc2))))
       const fiboi (gamma (n) (
           if (== n 0) 0 (fib-it n 0 1)))

       This  later  example is by far much faster, since it uses only one recursion. Although, it
       is no the fastest way to write it, it is still an elegant way to write complex functions.

       Other Integer methods
       The Integerclass offers other convenient methods. The odd-pand even-pare  predicates.  The
       modtake  one argument and returns the modulo between the calling integer and the argument.
       The absmethods returns the absolute value of the calling integer.

       i:even-p
       i:odd-p
       i:mod 2
       i:= -1
       i:abs
       i:to-string

       The Integerobject is a literal objectand a number object. As a  literal  object,  the  to-
       stringand to-literalmethods are provided to obtain a string representation for the integer
       object. Although the to-stringmethod  returns  a  string  representation  of  the  calling
       integer, the to-literalmethod returns a parsable string. Strictly speaking for an integer,
       there is no difference between a  string  representation  and  a  literal  representation.
       However, this is not true for other objects.

       (axi) const i 0x123
       (axi) println (i:to-string)
       291
       (axi) println (i:to-literal)
       291

       As  a number object, the integer number can also be represented in hexadecimal format. The
       to-hexaand to-hexa-strignmethods are designed to  obtained  such  representation.  In  the
       first  form, the to-hexamethod return a literal hexadecimal string representation with the
       appropriate prefix while the second one does not.

       (axi) const i 0x123
       (axi) println (i:to-hexa)
       0x123
       (axi) println (i:to-hexa-string)
       123

       Relatif number
       A relatifor big number is an integer with infinite precision. The Relatifclass is  similar
       to the Integerclass except that it works with infinitely long number. The relatif notation
       uses a ror Rsuffix to express a relatif number versus an integer one. The Relatifobject is
       a  literal  object  that  belongs  to  the number class. The predicate associated with the
       Relatifobject is relatif-p.

       const a  123R
       trans b -255R
       const c  0xffR
       const d  0b1111_1111R
       const e (Relatif)
       const f (Relatif 2000)
       const g (Relatif "23")

       Relatif operations
       Most of  the  Integerclass  operations  are  supported  by  the  Relatifobject.  The  only
       difference  is that there is no limitation on the number size. This naturally comes with a
       computational price. An amazing example is to compute  the  biggest  know  prime  Mersenne
       number. The world record exponent is 6972593. The number is therefore:

       const i 1R
       const m (- (i:shl 6972593) 1)

       This  number  has  2098960 digits. You can use the printlnmethod if you wish, but you have
       been warned...

       Real number
       The realclass implements the  representation  for  floating  point  number.  The  internal
       representation  is machine dependent, and generally follows the double representation with
       64 bits as specified by the IEEE 754-1985 standard for binary floating  point  arithmetic.
       All  integer operations are supported for real numbers. The Realobject is a literal object
       that belongs to the number class.

       Real format
       The parser supports two types  of  literal  representation  for  real  number.  The  first
       representation  is  the  dotted  decimalnotation.  The  second  notation is the scientific
       notation.

       const a  123.0 # a positive real
       const b -255.5 # a negative real
       const c  2.0e3 # year 2000.0

       Real number are constructed from the  literal  notation  or  by  using  an  explicit  real
       instance.  The  Realclass  offers standard constructors. The default constructor creates a
       real number object and initialize it to  0.0.  The  other  constructors  takes  either  an
       integer, a real number, a character or a string.

       Real arithmetic
       The  real  arithmetic  is  similar  to the integer one. When an integer is added to a real
       number, that number is automatically converted to  a  real.  Ultimately,  a  pure  integer
       operation might generate a real result.

       + 1999.0 1   # 2000.0
       + 1999.0 1.0 # 2000.0
       - 2000.0 1   # 1999.0
       - 2000.0 1.0 # 1999.0
       * 1000 2.0   # 2000.0
       * 1000.0 2.0 # 2000.0
       / 2000.0 2   # 1000.0
       / 2000.0 2.0 # 1000.0

       Like the Integerobject, the Realobject has arithmetic built-in methods.

       trans  r 0.0 # 0.0
       r:++       # 1.0
       r:--       # 0.0
       r:+ 4.0    # 4.0
       r:= 4.0    # 4.0
       r:- 1.0    # 3.0
       r:* 2.0    # 8.0
       r:/ 2.0    # 2.0
       r:+= 1.0   # 5.0
       r:-= 1.0   # 4.0
       r:*= 2.0   # 8.0
       r:/= 2.0   # 4.0

       Real comparison
       The comparison operators works as the integer one. As for the other operators, an implicit
       conversion between an integer to a real is done automatically.

       == 2000 2000   # true
       != 2000 1999   # true

       Comparison methods are also available for the Realobject. These  methods  take  either  an
       integer or a real as argument.

       r:=  1.0 # 1.0
       r:== 1.0 # true
       r:!= 0.0 # true

       A complex example
       One  of  the most interesting point with functional programming language is the ability to
       create complex function. For example let's assume we wish to compute the value at a  point
       xof  the  Legendre  polynomial  of  order n. One of the solution is to encode the function
       given its order. Another solution is to compute the function and then compute the value.

       # legendre polynomial order 0 and 1
       const lp-0 (gamma (x) 1)
       const lp-1 (gamma (x) x)
       # legendre polynomial of order n
       const lp-n (gamma (n) (
           if (> n 1) {
             const lp-n-1 (lp-n (- n 1))
             const lp-n-2 (lp-n (- n 2))
             gamma (x) (n lp-n-1 lp-n-2)
             (/ (- (* (* (- (* 2 n) 1) x)
                   (lp-n-1 x))
                 (* (- n 1) (lp-n-2 x))) n)
           } (if (== n 1) lp-1 lp-0)
         ))
       # generate order 2 polynomial
       const lp-2 (lp-n 2)
       # print lp-2 (2)
       println "lp2 (2) = " (lp-2 2)

       Note that the computation can be done either with integer or real numbers. With  integers,
       you  might  get  some  strange  results anyway, but it will work. Note also how the closed
       variable mechanism is used. The recursion capture each level of the polynomial until it is
       constructed. Note also that we have here a double recursion.

       Other real methods
       The   real  numbers  are  delivered  with  a  battery  of  functions.  These  include  the
       trigonometric functions, the logarithm and couple others. Hyperbolic functions like  sinh,
       cosh, tanh, asinh, acoshand atanhare also supported. The square root sqrtmethod return the
       square root of the calling real. The floorand ceilingreturns respectively  the  floor  and
       the ceiling of the calling real.

       const r0 0.0       # 0.0
       const r1 1.0       # 1.0
       const r2 2.0       # 2.0
       const rn -2.0      # -2.0
       const rq (r2:sqrt) # 1.414213
       const pi 3.1415926 # 3.141592
       rq:floor           # 1.0
       rq:ceiling         # 2.0
       rn:abs             # 2.0
       r1:log             # 0.0
       r0:exp             # 1.0
       r0:sin             # 0.0
       r0:cos             # 1.0
       r0:tan             # 0.0
       r0:asin            # 0.0
       pi:floor           # 3.0
       pi:ceiling         # 4.0

       Accuracy and formatting
       Real  numbers  are  not  necessarily accurate, nor precise. The accuracy and precision are
       highly dependent on the hardware as well as the nature of the operation  being  performed.
       In  any  case,  never  assume  that a real value is an exact one. Most of the time, a real
       comparison will fail, even if the numbers are very close  together.  When  comparing  real
       numbers,  it  is  preferable to use the ?=operator. Such operator result is bounded by the
       internal precision representation and will generally return the desired  value.  The  real
       precision is an interpreter value which is set with the set-absolute-precisionmethod while
       the get-absolute-precisionreturns the interpreter precision. There is also a set-relative-
       precisionand  get-relative-precisionmethods used for the definition of relative precision.
       By default, the absolute precision is set to 0.00001 and the relative precision is set  to
       1.0E-8.

       interp:set-absolute-precision 0.0001
       const r 2.0
       const s (r:sqrt) # 1.4142135
       (s:?= 1.4142)    # true

       Real  number formatting is another story. The formatmethod takes a precision argumentwhich
       indicates the number of digits to print for the decimal part. Note that the format command
       might round the result as indicated in the example below.

       const pi 3.1415926535
       pi:format 3  # 3.142

       If additional formatting is needed, the Stringfill-leftand fill-rightmethods can be used.

       const pi  3.1415926535        # 3.1415926535
       const val (pi:format 4)       # 3.1416
       println (val:fill-left '0' 9) # 0003.1416

       Number object
       The  Integer,  Relatifand  Realobjects  are  all  derived from the Numberobject which is a
       Literalobject. As such, the predicate number-pis the right mechanism to test an object for
       a  number.  The  class also provides the basic mechanism to format the number as a string.
       For integer and relatif, the hexadecimal representation can be obtained by the  to-hexaand
       to-hexa-stringmethods.  For  integer  and real numbers, the formatmethod adjusts the final
       representation with the precision argument as indicated before. It is worth to note that a
       formatted integer gets automatically converted into a real representation.

       Character
       The Characterobject is another built-in object. A character is internally represented by a
       quad by using a 31 bit representation as specified by the Unicode standard and ISO 10646.

       Character format
       The standard quote notation is used to represent a character. In that  respect,  there  is
       hare  a  substantial  difference  with other functional language where the quote protect a
       form.

       const LA01 'a' # the character a
       const ND10 '0' # the digit 0

       All characters from the Unicode codesetare supported by the  AFNIX engine. The  characters
       are  constructed from the literal notation or by using an explicit character instance. The
       Characterclass offers standard  constructors.  The  default  constructor  creates  a  null
       character.  The  other  constructors  take either an integer, a character or a string. The
       string can be either a single quoted character  or  the  literal  notation  based  on  the
       U+notation  in  hexadecimal.  For  example,  U+40is the @character while U+3A3is the sigma
       capital letter.

       const nilc (Character)        # null character
       const a    (Character 'a')    # a
       const 0    (Character 48)     # 0
       const mul  (Character "*")    # *
       const div  (Character "U+40") # @

       Character arithmetic
       A character is like an integer, except that it operates in the range 0 to 0x7FFFFFFF.  The
       character  arithmetic  is simpler compared to the integer one and no overflow or underflow
       checking is done. Note that the arithmetic operations take an integer as an argument.

       + 'a' 1 # 'b'
       - '9' 1 # '8'

       Several Characterobject methods are also provided  for  arithmetic  operations  in  a  way
       similar to the Integerclass.

       trans  c 'a' # 'a'
       c:++         # 'b'
       trans  c '9' # '9'
       c:--         # '8'
       c:+ 1        # '9'
       c:- 9        # '0'

       Character comparison
       Comparison operators are also working with the Characterobject. The standard operators are
       namely equal ==, not equal !=, less than <, less equal <=, greater >and greater equal  >=.
       These operators take two arguments.

       == 'a' 'b' # false
       != '0' '1' # true

       Other character methods
       The Characterobject comes with additional methods. These are mostly conversion methods and
       predicates. The to-stringmethod returns a string representation of the calling  character.
       The  to-integermethod  returns  an  integer  representation  the  calling  character.  The
       predicates are alpha-p, digit-p, blank-p, eol-p, eos-pand nil-p.

       const LA01 'a'  # 'a'
       const ND10 '0'  # '0'
       LA01:to-string  # "a"
       LA01:to-integer # 97
       LA01:alpha-p    # true
       ND10:digit-p    # true

       String
       The Stringobject is one of the most  important  built-in  object  in  the   AFNIX  engine.
       Internally,  a  string  is  a vector of Unicode characters. Because a string operates with
       Unicode characters, care should be taken when using composing characters.

       String format
       The standard double quote notation is used  to  represent  literally  a  string.  Standard
       escape sequences are also accepted to construct a string.

       const hello "hello"

       Any  literal  object  can  be  used  to construct a string. This means that integer, real,
       boolean or character objects are all valid to construct strings. The  default  constructor
       creates a null string. The string constructor can also takes a string.

       const nils (String)      # ""
       const one  (String 1)    # "1"
       const a    (String 'a')  # "a"
       const b    (String true) # "true"

       String operations
       The  Stringobject  provides  numerous  methods  and  operators.  The  most common ones are
       illustrated in the example below. The lengthmethods returns the total number of characters
       in  the  string object. It is worth to note that this number is not necessarily the number
       of printed characters  since  some  characters  might  be  combining  charactersused,  for
       example,  as  diacritics.  The non-combining-lengthmethod might be more adapted to get the
       number of printable characters.

       const h "hello"
       h:length       # 5
       h:get 0        # 'h'
       h:== "world"   # false
       h:!= "world"   # true
       h:+= " world"  # "hello world"

       The sub-leftand sub-rightmethods return a sub-string, given the position index.  For  sub-
       left,  the  index is the terminating index, while sub-rightis the starting index, counting
       from 0.

       # example of sub-left method
       const msg "hello world"
       msg:sub-left  5 # "hello"
       msg:sub-right 6 # "world"

       The strip, strip-leftand strip-rightare  methods  used  to  strip  blanks  and  tabs.  The
       stripmethod combines both strip-leftand strip-right.

       # example of strip method
       const str " hello world "
       println (str:strip) # "hello world"

       The  splitmethod  returns a vector of strings by splitting the string according to a break
       sequence. By default, the break sequence is the blank, tab  and  newline  characters.  The
       break sequence can be one or more characters passed as one single argument to the method.

       # example of split method
       const str "hello:world"
       const vec (str:split ":" # "hello" "world")
       println (vec:length) # 2

       The  fill-leftand  fill-rightmethods can be used to fill a string with a character up to a
       certain length. If the string is longer than the length, nothing happens.

       # example of fill-left method
       const pi  3.1415926535  # 3.1415926535
       const val (pi:format 4) # 3.1416
       val:fill-left '0' 9     # 0003.1416

       Conversion methods
       The case conversion methods are  the  standard  to-upperand  to-lowermethods.  The  method
       operates  with the internal Unicode database. As a result, the conversion might change the
       string length. Other conversion methods related to the  Unicode  representation  are  also
       available.  These are rather technical, but can be used to put the string in a normal form
       which might be suitable for comparison. Such conversion always uses the  Unicode  database
       normal form representation.

       # example of case conversion
       const str "hello world"
       println (str:to-upper) # HELLO WORLD

       String hash value
       The  hashidmethod  is a method that computes the hash value of a string. The value depends
       on the target machine and will change between a 32 bits and a  64  bits  machine.  Example
       example 0203.alsillustrates the computation of a hash value for our favorite test string.

       # test our favorite string
       const hello "hello world"
       hello:hashid # 1054055120

       The  algorithm  used  by  the  engine  is shown as an example below. As a side note, it is
       recommended to print the shift amount in the program.  One  may  notice,  that  the  value
       remains  bounded  by  24.  Since we are xoringthe final value, it does illustrate that the
       algorithm is design for a 32 bits machine.  With  a  64  bits  machine  the  algorithm  is
       slightly  modified  to  use  the extra space. This also means that the hashid value is not
       portable across platforms.

       # compute string hashid
       const hashid (s) {
         const len (s:length)
         trans cnt 0
         trans val 0
         trans sht 17
         do {
           # compute the hash value
           trans i (Integer (s:get cnt))
           val:= (val:xor (i:shl sht))
           # adjust shift index
           if (< (sht:-= 7) 0) (sht:+= 24)
         } (< (cnt:++) len)
         eval val
       }

       Regular expression
       A regular expression or regexis a special literal object designed to describe a  character
       string in a compact form with regular patterns. A regular expression provides a convenient
       way to perform pattern matching and filed extraction within a character string.

       Regex syntax
       A regular expression is defined with a special Regexobject. A regular  expression  can  be
       built  implicitly or explicitly with the use of the Regexobject. The regex syntax uses the
       [and ]characters as block delimiters. When used in a source file, the parser automatically
       recognizes  a  regex  and  built  the  object accordingly. The following example shows two
       equivalent methods for the same regex expression.

       # syntax built-in regex
       (== [$d+] 2000)         # true
       # explicit built-in regex
       (== (Regex "$d+") 2000) # true

       In its first form, the [and  ]characters  are  used  as  syntax  delimiters.  The  lexical
       analyzer  automatically  recognizes  this  token  as  a  regex  and  built  the equivalent
       Regexobject. The second form is the explicit construction of the  Regexobject.  Note  also
       that the [and ]characters are also used as regex block delimiters.

       Regex characters and meta-characters
       Any  character, except the one used as operators can be used in a regex. The $character is
       used as a meta-character -- or control character --  to  represent  a  particular  set  of
       characters. For example, [hello world]is a regex which match only the "hello world"string.
       The [$d+]regex matches one or more digits. The following meta characters are  built-in  in
       the regex engine.

       Character   Description
       $a          matches any letter or digit
       $b          matches any blank characters
       $c          matches any combining alphanumeric
       $d          matches any digit
       $e          matches eol, cr and eos
       $l          matches any lower case letter
       $n          matches eol or cr
       $s          matches any letter
       $u          matches any upper case letter
       $v          matches any valid afnix constituent
       $w          matches any word constituent
       $x          matches any hexadecimal characters

       The  uppercase  version is the complement of the corresponding lowercase character set.  A
       character which follows a $character and that is not a meta  character  is  treated  as  a
       normal  character.  For example $[is the [character. A quoted string can be used to define
       character matching which could otherwise be interpreted as control characters or operator.
       A quoted string also interprets standard escaped sequencesbut not meta characters.

       (== [$d+]   2000) # true
       (== ["$d+"] 2000) # false

       Combining  alphanumerical characters can generate surprising result when used with Unicode
       string. Combining alphanumeric characters are  alphanumeric  characters  and  non  spacing
       combining  mark as defined by the Unicode consortium. In practice, the combining marks are
       the diacritics used with regular letter, such  like  the  accents  found  in  the  western
       languages.  Because the writing system uses a canonical decomposition for representing the
       Unicode string, it turns out that the printed string is generally  represented  with  more
       bytes, making the string length longer than it appears.

       Regex character set
       A  character  set  is  defined with the <and >characters. Any enclosed character defines a
       character set. Note that meta characters are also interpreted inside a character set.  For
       example,  <$d+->represents  any  digit  or  a plus or minus. If the first character is the
       ^character in the character set, the character set is complemented  with  regards  to  its
       definition.

       Regex blocks and operators
       The  [and ]characters are the regex sub-expressions delimiters. When used at the top level
       of a regex definition, they can identify an implicit object. Their use at  the  top  level
       for explicit construction is optional. The following example is strictly equivalent.

       # simple real number check
       const real-1 (Regex "$d*.$d+")
       # another way with [] characters
       const real-2 (Regex "[$d*.$d+]")

       Sub-expressions  can  be nested -- that's their role -- and combined with operators. There
       is no limit in the nesting level.

       # pair of digit testing
       (== [$d$d[$d$d]+] 2000)  # true
       (== [$d$d[$d$d]+] 20000) # false

       The following unary operators can be used with single character,  control  characters  and
       sub-expressions.

       Operator   Description
       *          match 0 or more times
       +          match 1 or more times
       ?          match 0 or 1 time
       |          alternation

       Alternation  is  an  operator which work with a secondary expression. Care should be taken
       when writing the right  sub-expression.  For  example  the  following  regex  [$d|hello]is
       equivalent  to  [[$d|h]ello]. In other word, the minimal first sub-expression is used when
       compiling the regex.

       Grouping
       Groups of sub-expressions are created with the (and )characters. When a group is  matched,
       the  resulting sub-string is placed on a stack and can be used later. In this respect, the
       regex engine can be used to extract sub-strings. The following example extracts the month,
       day and year from a particular date format: [($d$d):($d$d):($d$d$d$d)]. This regex assumes
       a date in the form mm:dd:yyyy.

       if (== (const re [($d$d):($d$d)]) "12:31") {
         trans hr (re:get 0)
         trans mn (re:get 1)
       }

       Grouping is the mechanism to retrieve sub-strings when a match is successful. If the regex
       is bound to a symbol, the getmethod can be used to get the sub-string by index.

       Regex object
       Although  a regex can be built implicitly, the Regexobject can also be used to build a new
       regex. The argument is a string which  is  compiled  during  the  object  construction.  A
       Regexobject is a literal object. This means that the to-stringmethod is available and that
       a call to the printlnspecial form will work directly.

       const   re (Regex "$d+")
       println re           # $d+
       println re:to-string # [$d+]

       Regex operators
       The ==and !=operators are the primary operators to perform a regex match.  The  ==operator
       returns  trueif  the  regex  matches  the string argument from the beginning to the end of
       string. Such operator implies the begin and end of string anchoring. The <operator returns
       true if the regex matches the string or a sub-string or the string argument.

       Regex methods
       The  primary  regex  method  is the getmethod which returns by index the sub-string when a
       group has been matched. The lengthmethod returns the number of group match.

       if (== (const re [($d$d):($d$d)]) "12:31") {
         re:length # 2
         re:get 0  # 12
         re:get 1  # 31
       }

       The matchmethod returns the first string which is matched by the regex.

       const regex [$d+]
       regex:match "Happy new year 2000" # 2000

       The replacemethod any occurrence of the matching string with the string argument.

       const regex [$d+]
       regex:replace "Hello year 2000" "3000" # hello year 3000

       Argument conversion
       The use of the Regexoperators implies that the arguments are evaluated as literal  object.
       For  this  reason,  an  implicit  string conversion is made during such operator call. For
       example, passing the integer 12or the string "12"is strictly equivalent.  Care  should  be
       taken when using this implicit conversion with real numbers.

CONTAINER OBJECTS

       This  chapter covers the standard container objects and more specifically, iterableobjects
       such like Cons, Listand Vector. Special objects like Fifo, Queueand Bitsetare  treated  at
       the  end of this chapter. Although the name container is sufficient enough to describe the
       object functionality, it is clear that a container is more than a simple object reservoir.
       In  particular,  the  choice  of  a container object is often associated to the underlying
       algorithm used to store the object. For example, a vector is appropriate when  storing  by
       index is important. If the order of storage must be preserved, then a fifo object might be
       more appropriate. In any case,  the  choice  of  a  container  is  always  a  question  of
       compromise, so is the implementation.

       Cons object
       Originally,  a  Consobject  or  cons  cellhave  been the fundamental object of the Lisp or
       Scheme machine. The cons cell is the building block  for  list  and  is  similar  in  some
       respect to the cons cellfound in traditional functional programming language. A Consobject
       is a simple element used to build linked list. The cons cell holds an object and a pointer
       to  the next cons cell. The cons cell object is called carand the next cons cell is called
       the cdr. This original Lisp notation  is  maintained  here  for  the  sake  of  tradition.
       Although  a cons cell is the building block for single linked list, the cell itself is not
       a list object. When a list object is needed, the Listdouble linked list  object  might  be
       more appropriate.

       Cons cell constructors
       The  default  constructor  creates a cons cell those car is initialized to the nil object.
       The constructor can also take one or several objects.

       const nil-cons (Cons)
       const lst-cons (Cons 1 'a' "hello")

       The constructor can take any kind of objects. When all objects have  the  same  type,  the
       result  list  is  said  to  be  homogeneous. If all objects do not have the same type, the
       result list is said to be heterogeneous. List can also  be  constructed  directly  by  the
       parser.  Since  all  internal  forms  are  built  with  cons cell, the construction can be
       achieved by simply protectingthe form from being interpreted.

       const blist (protect ((1) ((2) ((3)))))

       Cons cell methods
       A Consobject provides several methods to access the carand the cdrof a  cons  cell.  Other
       methods allows access to a list by index.

       const c (Cons "hello" "world")
       c:length   # 2
       c:get-car  # "hello"
       c:get-cadr # "world"
       c:get 0    # "hello"
       c:get 1    # "world"

       The  set-carmethod set the car of the cons cell. The addmethod adds a new cons cell at the
       end of the cons list and set the car with the specified object.

       List object
       The Listobject provides the facility of a double-link  list.  The  Listobject  is  another
       example  of  iterable  object.  The  Listobject  provides support for forward and backward
       iteration.

       List construction
       A list is constructed like a cons cell with zero or more arguments. Unlike the cons  cell,
       the Listcan have a null size.

       const nil-list (List)
       const dbl-list (List 1 'a' "hello")

       List methods
       The Listobject methods are similar the Consobject. The addmethod adds an object at the end
       of the list. The insertmethod inserts an object at the beginning of the list.

       const list (List "hello" "world")
       list:length      # 2
       list:get 0       # "hello"
       list:get 1       # "world"
       list:add "folks" # "hello" "world" "folks"

       Vector object
       The Vectorobject provides the facility of an index array of objects. The  Vectorobject  is
       another  example  of  iterable  object.  The Vectorobject provides support for forward and
       backward iteration.

       Vector construction
       A vector is constructed like a cons cell or a list.  The  default  constructor  creates  a
       vector with 0 objects.

       const nil-vector (Vector)
       const obj-vector (Vector 1 'a' "hello")

       Vector methods
       The Vectorobject methods are similar to the Listobject. The addmethod appends an object at
       the end of the vector. The setmethod set a vector position by index.

       const vec (Vector "hello" "world")
       vec:length          # 2
       vec:get 0           # "hello"
       vec:get 1           # "world"
       vec:add "folks"     # "hello" "world" "folks"
       vec:set 0 "bonjour" # "bonjour" "world" "folks"

       Set object
       The Setobject provides the facility of an  object  container.  The  Setobject  is  another
       example  of  iterable object. The Setobject provides support for forward iteration. One of
       the property of a set is that there is only one object representation per set. Adding  two
       times the same object results in one object only.

       Set construction
       A set is constructed like a vector. The default constructor creates a set with 0 objects.

       const nil-set (Set)
       const obj-set (Set 1 'a' "hello")

       Set methods
       The Setobject methods are similar to the Vectorobject. The addmethod adds an object in the
       set. If the object is already in the set,  the  object  is  not  added.  The  lengthmethod
       returns the number of elements in the set.

       const set       (Set "hello" "world")
       set:get-size    # 2
       set:add "folks" # "hello" "world" "folks"

       Iteration
       When  an  object is iterable, it can be used with the reserved keyword for. The forkeyword
       iterates on one or several objects and binds associated symbols during each  step  of  the
       iteration process. All iterable objects provides also the method get-iteratorwhich returns
       an iterator for a  given  object.  The  use  of  iterator  is  justified  during  backward
       iteration, since foronly perform forward iteration.

       Function mapping
       Given  a  function func, it is relatively easy to apply this function to all objects of an
       iterable object. The result is a list of successive calls with the function. Such function
       is called a mapping function and is generally called map.

       const map (obj func) {
         trans result (Cons)
         for (car) (obj) (result:link (func car))
         eval result
       }

       The linkmethod differs from the addmethod in the sense that the object to append is set to
       the cons cell car if the car and cdr is nil.

       Multiple iteration
       Multiple iteration can be done with one call to for. The computation of a  scalar  product
       is a simple but illustrative example.

       # compute the scalar product of two vectors
       const scalar-product (u v) {
         trans result 0
         for (x y) (u v) (result:+= (* x y))
         eval result
       }

       Note  that  the  function  scalar-productdoes  not make any assumption about the object to
       iterate. One could compute the scalar product between a vector a list for example.

       const u (Vector 1 2 3)
       const v (List   2 3 4)
       scalar-product u v

       Conversion of iterable objects
       The use of an iterator is suitable for direct conversion between one object  and  another.
       The conversion to a vector can be simply defined as indicted below.

       # convert an iterable object to a vector
       const to-vector (obj) {
         trans result (Vector)
         for (i) (obj) (result:add i)
         eval result
       }

       Explicit iterator
       An  explicit  iterator  is  constructed  with the get-iteratormethod. At construction, the
       iterator is reset to the beginning position. The get-objectmethod returns  the  object  at
       the  current  iterator  position.  The nextadvances the iterator to its next position. The
       valid-pmethod returns trueif the iterator is  in  a  valid  position.  When  the  iterator
       supports  backward  operations, the prevmethod move the iterator to the previous position.
       Note that Consobjects do  not  support  backward  iteration.  The  beginmethod  reset  the
       iterator to the beginning. The endmethod moves the iterator the last position. This method
       is available only with backward iterator.

       # reverse a list
       const reverse-list (obj) {
         trans result (List)
         trans itlist (obj:get-iterator)
         itlist:end
         while (itlist:valid-p) {
           result:add (itlist:get-object))
         itlist:prev
       }
       eval result
       }

       Special Objects
       The engine incorporates other container objects. To name  a  few,  such  objects  are  the
       Queue, Bitsetor Fifoobjects.

       Queue object
       A  queueis  a special object which acts as container with a fifo policy. When an object is
       placed in the queue, it remains there until it has been dequeued. The Fifoand Queueobjects
       are  somehow  similar,  with  the  fundamental  difference that the queue resize itself if
       needed.

       # create a queue with objects
       const q (Queue "hello" "world")
       q:empty-p # false
       q:length  # 2
       # dequeue some object
       q:dequeue # hello
       q:dequeue # world
       q:empty-p # true

       Bitset object
       A bit setis a special container for bit. A bit set can  be  constructed  with  a  specific
       size.  When  the  bit  set  is  constructed,  each  bit can be marked and tested by index.
       Initially, the bitset size is null.

       # create a bit set by size
       const bs (Bitset 8)
       bitset-p bs # true
       # check, mark and clear
       assert false (bs:marked-p 0)
       bs:mark 0
       assert true  (bs:marked-p 0)
       bs:clear 0
       assert false (bs:marked-p 0)

CLASSES

       This chapter covers the class model and its associated  operations.  The  class  model  is
       slightly  different  compared  to  traditional  one because dynamic symbol bindings do not
       enforce to declare the class data members. A class is an object which can  be  manipulated
       by  itself.  Such  class  is said to belongs to a group of meta classas described later in
       this chapter. Once the class concept has been detailed, the chapter moves to  the  concept
       of  instance  of that class and shows how instance data members and functions can be used.
       The chapter terminates with a description of dynamic class programming.

       Class object
       A class objectis simply a nameset which can be replicated via a construction mechanism.  A
       class  is  created with the special form class. The result is an object of type Classwhich
       supports various symbol binding operations.

       Class declaration and bindings
       A new class is an object created with the reserved keyword class. Such class is an  object
       which can be bound to a symbol.

       const Color (class)

       Because  a  class  acts  like  a nameset, it is possible to bind directly symbols with the
       qualified namenotation.

       const Color (class)
       const Color:RED-FACTOR   0.75
       const Color:BLUE-FACTOR  0.75
       const Color:GREEN-FACTOR 0.75

       When a data is defined in the class nameset, it is common to refer  it  as  a  class  data
       member.  A  class  data member is invariant over the instance of that class. When the data
       member is declared with the constreserved keyword, the symbol  binding  is  in  the  class
       nameset.

       Class closure binding
       A  lambda  or gamma expression can be define for a class. If the class do not reference an
       instance of that class, the resulting closure is called a class methodof that class. Class
       methods  are  invariant  among  the class instances. The standard declaration syntax for a
       lambda or gamma expression is still valid with a class.

       const Color:get-primary-by-string (color value) {
         trans val "0x"
         val:+= (switch color (
             ("red"   (value:substr 1 3))
             ("green" (value:substr 3 5))
             ("blue"  (value:substr 5 7))
           ))
         Integer val
       }

       The invocation of a class method is done with the standard qualified namenotation.

       Color:get-primary-by-string "red"   "#23c4e5"
       Color:get-primary-by-string "green" "#23c4e5"
       Color:get-primary-by-string "blue"  "#23c4e5"

       Class symbol access
       A class acts as a nameset and therefore provides the mechanism to evaluate any symbol with
       the qualified name notation.

       const Color:RED-VALUE "#ff0000"
       const Color:print-primary-colors (color) {
         println "red   color " (
           Color:get-primary-color "red"   color)
         println "green color " (
           Color:get-primary-color "green" color)
         println "blue  color " (
           Color:get-primary-color "blue"  color)
       }
       # print the color components for the red color
       Color:print-primary-colors Color:RED-VALUE

       Instance
       An instanceof a class is an object which is constructed by a special class method called a
       constructor. If an instance constructor does not exist, the instance is  said  to  have  a
       default  construction.  An  instance  acts  also  as a nameset. The only difference with a
       class, is that a symbol resolution is done first in the instance nameset and then  in  the
       instance  class.  As a consequence, creating an instance is equivalent to define a default
       nameset hierarchy.

       Instance construction
       By default, a instance of the class is an object which defines an  instance  nameset.  The
       simplest way to define an anonymous instance is to create it directly.

       const i     ((class))
       const Color (class)
       const red   (Color)

       The  example above define an instance of an anonymous class. If a class object is bound to
       a symbol, such symbol can be used to create an instance of that class. When an instance is
       created,  the  special symbol named thisis defined in the instance nameset. This symbol is
       bounded to the instance object and can be used  to  reference  in  an  anonymous  way  the
       instance itself.

       Instance initialization
       When  an  instance  is  created,  the  engine looks for a special lambda expression called
       preset. This lambda expression, if it exists, is executed after the default  instance  has
       been  constructed. Such lambda expression is a method since it can refer to the thissymbol
       and bind some instance symbols.  The  arguments  which  are  passed  during  the  instance
       construction are passed to the presetmethod.

       const Color (class)
       trans Color:preset (red green blue) {
         const this:red   (Integer red)
         const this:green (Integer green)
         const this:blue  (Integer blue)
       }
       # create some default colors
       const Color:RED   (Color 255   0   0)
       const Color:GREEN (Color   0 255   0)
       const Color:BLUE  (Color   0   0 255)
       const Color:BLACK (Color   0   0   0)
       const Color:WHITE (Color 255 255 255)

       In  the example above, each time a color is created, a new instance object is created. The
       constructor is invoked with the thissymbol bound to the newly created instance. Note  that
       the  qualified  name  this:reddefines a new symbol in the instance nameset. Such symbol is
       sometimes referred as an instance data member. Note as well that there is no ambiguity  in
       resolving  the  symbol  red.  Once  the symbol is created, it shadows the one defined as a
       constructor argument.

       Instance symbol access
       An instance acts as a nameset. It is therefore possible to bind locally to an  instance  a
       symbol.  When  a  symbol needs to be evaluated, the instance nameset is searched first. If
       the symbol is not found, the class nameset is searched. When  an  instance  symbol  and  a
       class  symbol  have the same name, the instance symbol is said to shadow the class symbol.
       The simple example below illustrates this property.

       const c   (class)
       const c:a 1
       const i   (c)
       const j   (c)
       const i:a 2
       # class symbol access
       println   c:a
       # shadow symbol access
       println   i:a
       # non shadow access
       println   j:a

       When the instance is created, the special symbol metais bound in the instance nameset with
       the instance class object. This symbol can therefore be used to access a shadow symbol.

       const c   (class)
       const i   (c)
       const c:a 1
       const i:a 2
       println   i:a
       println   i:meta:a

       The  symbol metamust be used carefully, especially inside an initialization since it might
       create an infinite recursion as shown below.

       const c (class)
       trans c:preset nil (const i (this:meta))
       const i (c)

       Instance method
       When lambda expression is defined within the class or the instance  nameset,  that  lambda
       expression  is  callable  from  the  instance  itself.  If  the lambda expression uses the
       thissymbol, that lambda is called an instance method since the symbol  thisis  defined  in
       the instance nameset. If the instance method is defined in the class nameset, the instance
       method is said to be global, that is, callable by any  instance  of  that  class.  If  the
       method  is defined in the instance nameset, that method is said to be localand is callable
       by the instance only. Due to the  nature  of  the  nameset  parent  binding,  only  lambda
       expression can be used. Gamma expressions will not work since the gamma nameset has always
       the top level nameset as its parent one.

       const Color (class)
       # class constructor
       trans Color:preset (red green blue) {
         const this:red   (Integer red)
         const this:green (Integer green)
         const this:blue  (Integer blue)
       }
       const Color:RF 0.75
       const Color:GF 0.75
       const Color:BF 0.75
       # this method returns a darker color
       trans Color:darker nil {
         trans lr (Integer (max (this:red:*   Color:RF) 0))
         trans lg (Integer (max (this:green:* Color:GF) 0))
         trans lb (Integer (max (this:blue:*  Color:BF) 0))
         Color lr lg lb
       }
       # get a darker color than yellow
       const yellow      (Color 255 255 0)
       const dark-yellow (yellow:darker)

       Instance operators
       Any operator can be defined at the class  or  the  instance  level.  Operators  like  ==or
       !=generally  requires  the  ability  to  assert if the argument is of the same type of the
       instance. The global operator ==will return true if two classes are the same. With the use
       of the metasymbol, it is possible to assert such equality.

       # this method checks that two colors are equals
       trans Color:== (color) {
         if (== Color color:meta) {
           if (!= this:red   color:red)   (return false)
           if (!= this:green color:green) (return false)
           if (!= this:blue  color:blue)  (return false)
           eval true
         } false
       }
       # create a new yellow color
       const  yellow (Color 255 255 0)
       (yellow:== (Color 255 255 0)) # true

       The global operator ==returns trueif both arguments are the same, even for classes. Method
       operators are left open to the user.

       Complex number example
       As a final example, a  class  simulating  the  behavior  of  a  complex  number  is  given
       hereafter.  The  interesting  point  to  note  is the use of the operators. As illustrated
       before, the class uses uses a default method method to initialize the data members.

       # class declaration
       const Complex (class)
       # constructor
       trans Complex:preset (re im) {
         trans this:re (Real re)
         trans this:im (Real im)
       }

       The constructor creates a complex object with the help of the real part and the  imaginary
       part. Any object type which can be bound to a Realobject is acceptable.

       # class mutators
       trans Complex:set-re (x) (trans this:re (Real re))
       trans Complex:set-im (x) (trans this:im (Real im))
       # class accessors
       trans Complex:get-re nil (Real this:re)
       trans Complex:get-im nil (Real this:im)

       The  accessors  and  the  mutators  simply  provides  the  interface to the complex number
       components and perform a cloning of the calling or returned objects.

       # complex number module
       trans Complex:module nil {
         trans result (Real (+ (* this:re this:re)
             (* this:im this:im)))
         result:sqrt
       }
       # complex number formatting
       trans Complex:format nil {
         trans result (String this:re)
         result:+= "+i"
         result:+= (String this:im)
       }

       The moduleand formatare  simple  methods.  Note  the  the  complex  number  formatting  is
       arbitrary here.

       # complex predicate
       const complex-p (c) (
         if (instance-p c) (== Complex c:meta) false)

       The  complex-ppredicate is the perfect illustration of the use of the metareserved symbol.
       However, it shall be noted that the meta-comparison is done if and  only  if  the  calling
       argument is an instance.

       # operators
       trans Complex:== (c) (
         if (complex-p c) (and (this:re:== c:re)
           (this:im:== c:im)) (
           if (number-p c)  (and (this:re:== c)
             (this:im:zero-p)) false))
       trans Complex:= (c) {
         if (complex-p c) {
           this:re:= (Real c:re)
           this:im:= (Real c:im)
           return this
         }
         this:re:= (Real c)
         this:im:= 0.0
         return this
       }
       trans Complex:+ (c) {
         trans result (Complex this:re this:im)
         if (complex-p c) {
           result:re:+= c:re
           result:im:+= c:im
           return result
         }
         result:re:+= (Real c)
         eval result
       }

       The  operators  are  a  little tedious to write. The comparison can be done with a complex
       number or a built-in number object. The assignation operator creates a copy for  both  the
       real and imaginary part. The summation operator is given here for illustration purpose.

       Inheritance
       Inheritance  is  the  mechanism  by which a class or an instance inherits methods and data
       member access from a parent object. The class model  is  based  on  a  single  inheritance
       model.  When  an  instance  object  defines a parent object, such object is called a super
       instance. The instance which has a super instance is called a derived instance.  The  main
       utilization of inheritance is the ability to reuse methods for that super instance.

       Derivation construction
       A  derived object is generally defined within the presetmethod of that instance by setting
       the  superdata  member.  The  superreserved  keyword  is  set  to  nil  at  the   instance
       construction.  The  good  news  is  that  any  object  can be defined as a super instance,
       including built-in object.

       const c (class)
       const c:preset nil {
         trans this:super 0
       }

       In the example above, an instance of class cis constructed. The super instance is with  an
       integer  object.  As  a  consequence,  the  instance  is derived from the Integerinstance.
       Another consequence of this scheme is that derived instance do not have to be  built  from
       the same base class.

       Derived symbol access
       When  an  instance  is  derived  from  another  one, any symbol which belongs to the super
       instance can be access with the use of the  superdata  member.  If  the  super  class  can
       evaluate a symbol, that symbol is resolved automatically by the derived instance.

       const c       (class)
       const i       (c)
       trans i:a     1
       const j       (c)
       trans j:super i
       println j:a

       When  a  symbol  is  evaluated,  a  set  of  search rules is applied. The engine gives the
       priority to the class nameset vs the super instance. As a consequence, a class data member
       might  shadow  a  super instance data member. The rule associated with a symbol evaluation
       can be summarized as follow.
              Look in the instance nameset.
              Look in the class nameset.
              Look in the super instance if it exists.
              Look in the base object.

       Instance re-parenting
       The ability to set dynamically  the  parent  instance  make  the  object  model  an  ideal
       candidate to support instance re-parenting. In this model, a change in the parent instance
       is automatically reflected at the instance method call.

       const c (class)
       const i (c)
       trans i:super 0
       println (i:to-string) # 0
       trans i:super "hello world"
       println (i:to-string) # hello world

       In this example, the instance is originally set with an Integerinstance parent.  Then  the
       instance  is  re-parentedwith  a  Stringinstance  parent.  The call to the to-stringmethod
       illustrates this behavior.

       Instance re-binding
       The ability to set dynamically the instance class is another powerful feature of the class
       model.  In  this  approach,  the  instance  meta class can be changed dynamically with the
       mutemethod. Furthermore, it is also possible to create initially an instance  without  any
       class binding, which is later muted.

       # create a point class
       const  point (class)
       # point class
       trans point:preset (x y) {
         trans this:x x
         trans this:y y
       }
       # create an empty instance
       const p (Instance)
       # bind the point class
       p:mute point 1 2

       In this example, when the instance is muted, the presetmethod is called automatically with
       the extra arguments.

       Instance inference
       The ability to instantiate dynamically inferred instance is offered by the instance model.
       An  instance  bis  said  to  be  inferred by the instance awhen the instance ais the super
       instance of the instance b. The instance inference is obtained by binding the  infersymbol
       to  a  class.  When  an  instance  of that class is created, the inferred instance is also
       created.

       # base class A
       const A  (class)
       # inferred class B
       const B  (class)
       const A:infer B
       # create an instance from A
       const  x (A)
       assert B (x:meta)
       assert A (x:super:meta)

       In this example, when the instance is created, the inferred instance is also  created  and
       returned  by  the  instantiation process. The presetmethod is only called for the inferred
       instance if possible or the base instance if there is no inferring class. Because the base
       presetpreset  method is not called automatically, the inferred method is responsible to do
       such call.

       trans B:preset (x y) {
         trans this:xb x
         trans this:yb y
         if (== A this:super:meta) (this:super:preset x y)
       }

       Because the class can mute from one call to another  and  also  the  inferred  class,  the
       presetmethod  call  must be used after a discrimination of the meta class has been made as
       indicated by the above example.

       Instance deference
       In the process of creating instances, one might have a generic class with  a  method  that
       attempts  to  access  a  data member which is bound to another class. The concept of class
       deferenceis exactly designed for this purpose. With the help of reserved keyword defer,  a
       class  with virtual data member accessors can be bound to a base class as indicated in the
       example below.

       # create the base and defer class
       const bc (class)
       const dc (class)
       # bind the base preset method
       trans bc:preset nil (const this:y 2)
       # bind the defer accessor to the base data member
       trans dc:get-y nil (eval this:y)
       # bind the defer class in the base class
       const bc:defer dc
       # create an instance from the base class
       const i (bc)
       # access to the base member with the defer method
       assert 2 (i:get-y)

       It is worth to note that the class deference is made at the class level. When an  instance
       of  the  base  class is created, all methods associated with the deferentclass are visible
       from the base class, thus making the deferentclass a virtual interface to the base class.

ADVANCED CONCEPTS

       This chapter covers advanced concepts of the writing system.  The  first  subject  is  the
       exception  model. The second subject covers some properties of the namesets in the context
       of the interpreter object.  The  thread  sub-system  is  then  described  along  with  the
       synchronization  mechanism. Finally, some notes related to the functional system are given
       at the end of this chapter.

       Exception
       An exceptionis an unexpected change in the execution flow. The exception model is based on
       a  mechanism  which  throws the exception to be caught by a handler. The mechanism is also
       designed to be compatible with the native "C++" implementation.

       Throwing an exception
       An exception is thrown with the reserved keyword throw. When an exception is  thrown,  the
       normal  flow  of  execution  is  interrupted  and  an  object  used to carry the exception
       information is created. Such exception object is propagated backward  in  the  call  stack
       until an exception handler catch it.

       if (not (number-p n))
       (throw "type-error" "invalid object found" n)

       The example above is the general form to throw an exception. The first argument is the the
       exception id. The second argument is the exception  reason.  The  third  argument  is  the
       exception  object.  The  exception id and reason are always a string. The exception object
       can be any object which is carried by the exception. The reserved keyword  throwaccepts  0
       or more arguments.

       throw
       throw "type-error"
       throw "type-error" "invalid argument"

       With  0  argument,  the exception is thrown with the exception id set to "user-exception".
       With one argument, the argument is the exception id. With 2 arguments,  the  exception  id
       and  reason  are  set.  Within  a try block, an exception can be thrown again by using the
       exception object represented with the whatsymbol.

       try {
         ...
       } {
         println "exception caught and re-thrown"
         throw what
       }

       Exception handler
       The special form tryexecutes a form and catch an exception if one has  been  thrown.  With
       one  argument,  the  form  is  executed and the result is the result of the form execution
       unless an exception is caught. If an exception is caught,  the  result  is  the  exception
       object. If the exception is a native one, the result is nil.

       try (+ 1 2)
       try (throw)
       try (throw "hello")
       try (throw "hello" "world")
       try (throw "hello" "world" "folks")

       In  its  second  form,  the tryreserved keyword can accept a second form which is executed
       when an exception is caught. When an exception is caught, a new nameset is created and the
       special  symbol  whatis  bounded  with  the  exception  object.  In  such environment, the
       exception can be evaluated.

       Symbol   Description
       eid      Exception id
       name     Exception file name
       line     Exception line number
       about    Exception extended reason
       reason   Exception reason
       object   Exception object

       try (throw "hello")
       (eval what:eid)
       try (throw "hello" "world")
       (eval what:reason)
       try (throw "hello" "world" 2000)
       (eval what:object)

       Exceptions are useful to notify abruptly  that  something  went  wrong.  With  an  untyped
       language,  it is also a convenient mechanism to abort an expression call if some arguments
       do not match the expected types.

       # protected factorial
       const fact (n) {
         if (not (integer-p n))
         (throw "number-error" "invalid argument in fact")
         if (== n 0) 1 (* n (fact (- n 1)))
       }
       try (fact 5) 0
       try (fact "hello") 0

       Nameset
       A  nameset  is  created  with  the  reserved  keyword  nameset.  Without   argument,   the
       namesetreserved keyword creates a nameset without setting its parent. With one argument, a
       nameset is created and the parent set with the argument.

       const nset (nameset)
       const nset (nameset ...)

       Default namesets
       When a nameset is created, the symbol .is automatically created and  bound  to  the  newly
       created  nameset.  If a parent nameset exists, the symbol ..is also automatically created.
       The use of the current nameset is a useful notation to resolve a particular name  given  a
       hierarchy of namesets.

       trans a 1 # 1
       block {
         trans   a (+ a 1) # 2
         println ..:a 1    # 1
       }
       println a           # 1

       Nameset and inheritance
       When  a  nameset  is  set as the super object of an instance, some interesting results are
       obtained. Because symbols are resolved in the nameset hierarchy, there is no limitation to
       use  a  nameset  to  simulate  a  kind  of  multiple  inheritance.  The  following example
       illustrates this point.

       const   cls (class)
       const   ins (cls)
       const   ins:super (nameset)
       const   ins:super:value 2000
       const   ins:super:hello "hello world "
       println ins:hello ins:value # hello world 2000

       Delayed Evaluation
       The engine provides a mechanism called delayed  evaluation.  Such  mechanism  permits  the
       encapsulation of a form to be evaluated inside an object called a promise.

       Creating a promise
       The  reserved  keyword delaycreates a promise. When the promise is created, the associated
       object is not evaluated. This means that the promise evaluates to itself.

       const a (delay (+ 1 2))
       promise-p a # true

       The previous example creates a promise and store the argument form. The form  is  not  yet
       evaluated. As a consequence, the symbol aevaluates to the promise object.

       Forcing a promise
       The  reserved  keyword forcethe evaluation of a promise. Once the promise has been forced,
       any further call will produce the same result. Note also that, at this stage, the  promise
       evaluates to the evaluated form.

       trans   y 3
       const   l ((lambda (x) (+ x y)) 1)
       assert  4 (force l)
       trans   y 0
       assert  4 (force l)

       Enumeration
       Enumeration, that is, named constant bound to an object, can be declared with the reserved
       keyword enum. The enumeration is built with a list of literal and evaluated as is.

       const  e    (enum E1 E2 E3)
       assert true (enum-p e)

       The complete  enumeration  evaluates  to  an  Enumobject.  Once  built,  enumeration  item
       evaluates by literal and returns an Itemobject.

       assert true   (item-p e:E1)
       assert "Item" (e:E1:repr)

       Items  are  comparable  objects.  Only items can be compared. For a given item, the source
       enumeration can be obtained with the get-enummethod.

       # check for item equality
       const i1 e:E1
       const i2 e:E2
       assert true  (i1:== i1)
       assert false (== i1 i2)
       # get back the enumeration
       assert true (enum-p (i1:get-enum))

       Logger
       The Loggerclass is a message logger that stores messages in a buffer  with  a  level.  The
       default  level  is the level 0. A negative level generally indicates a warning or an error
       message but this is just a convention which is not enforced by the  class.  A  high  level
       generally  indicates  a  less  important  message.  The  messages are stored in a circular
       buffer. When the logger is full, a new message replace the oldest  one.  By  default,  the
       logger is initialized with a 256 messages capacity that can be re-sized.

       const log    (Logger)
       assert true  (logger-p log)

       When  a  message  is added, the message is stored with a time-stamp and a level. The time-
       stamp is used later to format a message. The lengthmethod returns  the  number  of  logged
       messages.  The  get-messagemethod  returns a message by index. Because the system operates
       with a circular buffer, the get-messagemethod manages the indexes in such way that the old
       messages  are  accessible  with  the  oldest  index.  For  example,  even  after  a buffer
       circulation, the index 0 will point to the oldest  message.  The  get-message-levelreturns
       the message level and the get-message-timereturns the message posted time.

       const mesg (log:get-message 0)

       In term of usage, the logger facility can be conveniently used with other derived classes.
       The standard i/o module provides several classes that permits to manage logging operations
       in a convenient way.

       Interpreter
       The  interpreter  is by itself a special object with specialized methods which do not have
       equivalent using the standard notation.  The  interpreter  is  always  referred  with  the
       special  symbol  interp. The following table is a summary of the symbols and methods bound
       to the interpreter.

       Symbol          Description
       argv            Command arguments vector
       os-name         Operating system name
       os-type         Operating system type
       version         Full version
       loader          The interpreter loader
       resolver        The interpreter resolver
       afnix-uri       Official uri name
       program-name    Interpreter program name
       major-version   Major version number
       minor-version   Minor version number
       patch-version   Patch version number
       machine-size    The interpreter machine size

       Symbol                   Description
       dup                      duplicate the interpreter
       roll                     run the interpreter loop
       wait                     Wait for normal threads
       load                     Load a file and execute it
       launch                   Launch a normal thread
       daemon                   Launch a daemon thread
       library                  Load and initialize a library
       read-line                Get an input stream line
       read-passphrase          Get an input stream passphrase
       set-absolute-precision   Set absolute precision
       set-relative-precision   Set relative precision
       get-absolute-precision   Get absolute precision
       get-relative-precision   Get relative precision

       Arguments vector
       The interp:argvqualified name evaluates to a vector of strings. Each argument is stored in
       the vector during the interpreter initialization.

       zsh> axi hello world
       (axi) println (interp:argv:length) # 2
       (axi) println (interp:argv:get 0)  # hello

       Interpreter version
       Several symbols can be used to track the interpreter version and the operating system. The
       full version is bound to the interp:versionqualified name. The full version is composed of
       the  major, minorand patchnumber. The operating system name is bound to the qualified name
       interp:os-name. The operating system type is bound to the interp:os-type.

       println "major number   : " interp:major-version
       println "minor number   : " interp:minor-version
       println "patch number   : " interp:patch-version
       println "version number : " interp:version
       println "system name    : " interp:os-name
       println "system type    : " interp:os-type
       println "official uri   : " interp:afnix-uri

       Method load
       The interp:loadmethod loads and  execute  a  file.  The  interpreter  interactive  command
       session is suspended during the execution of the file. In case of error or if an exception
       is raised, the file execution is terminated. The process used to load a file  is  governed
       by  the  file  resolver.  Without  extension, a compiled file is searched first and if not
       found a source file is searched.

       Method library
       The interp:librarymethod loads and initializes a library. The interpreter maintains a list
       of  opened  library.  Multiple execution of this method for the same library does nothing.
       The method returns the library object.

       interp:library "afnix-sys"
       println "random number: " (afnix:sys:get-random)

       Method dup
       The interpreter can be duplicated with the help of  the  dupmethod.  Without  argument,  a
       clone  of  the  current  interpreter is made and a terminal object is attached to it. When
       used in conjunction with the rollmethod, this approach permits to  create  an  interactive
       interpreter. The dupmethod also accepts a terminal object.

       # duplicate the interpreter
       const si (interp:dup)
       # change the primary prompt
       si:set-primary-prompt "(si)"

       Method roll
       The  interpreter  loop  can  be  run  with  the  roll.  The  loop  operates by reading the
       interpreter input stream. If the  interpreter  has  been  cloned  with  the  help  of  the
       dupmethod,  this  method  provides  a  convenient  way to operate in interactive mode. The
       method is not called loopbecause it is a reserved keyword and  starting  a  loop  is  like
       having the ball rolling.

       # duplicate the interpreter
       const si (interp:dup)
       # loop with this interpreter
       si:roll

       Method wait
       The interpreter can wait for all normal threads to complete. When invoked, the interpreter
       monitors all normal threads and wait unil the  terminate  normally.  This  is  a  standard
       synchronization method in a multithreaded environment.

       # create a thread
       launch f
       # wait for completion
       interp:wait

       Librarian object
       A librarian fileis a special file that acts as a containers for various files. A librarian
       file is created with the axl--  cross  librarian  --utility.  Once  a  librarian  file  is
       created,  it  can be added to the interpreter resolver. The file access is later performed
       automatically by name with the standard interpreter loadmethod.

       Creating a librarian
       The axlutility is the preferred  way  to  create  a  librarian.  Given  a  set  of  files,
       axlcombines them into a single one.

       zsh: axl -h
       usage: axl [options] [files]
       [h]      print this help message
       [v]      print version information
       [c]      create a new librarian
       [x]      extract from the librarian
       [s]      get file names from the librarian
       [t]      report librarian contents
       [f] lib  set the librarian file name

       The  coption  creates  a  new  librarian.  The  librarian  file name is specified with the
       foption.

       zsh: axl -c -f librarian.axl file-1.als file-2.als

       The  previous  command  combines  file-1.alsand  file-2.alsinto  a  single   file   called
       librarian.axl. Note that any file can be included in a librarian.

       Using the librarian
       Once  a  librarian  is  created,  the  interpreter -ioption can be used to specify it. The
       -ioption accepts either a directory name or a librarian file. Once the librarian has  been
       opened, the interpreter loadmethod can be used as usual.

       zsh> axi -i librarian.axl
       (axi) interp:load "file-1.als"
       (axi) interp:load "file-2.als"

       The  librarian  acts  like  a  file  archive.  The interpreter file resolver takes care to
       extract the file from the librarian when the loadmethod is invoked.

       Librarian contents
       The axlutility provides the -tand  -soptions  to  look  at  the  librarian  contents.  The
       -soption  returns  all  file  name  in  the  librarian.  The  -toption  returns a one line
       description for each file in the librarian.

       zsh: axl -t -f librarian.axl
       --------       1234 file-1.als
       --------       5678 file-2.als

       The one line report contains the file flags, the file size and the  file  name.  The  file
       flags  are  not used at this time. One possible use in the future is for example, an auto-
       load bitor any other useful things.

       Librarian extraction
       The -xoption permits to extract file from the librarian. Without any  file  argument,  all
       files are extracted. With some file arguments, only those specified files are extracted.

       zsh: axl -x -f librarian.axl
       zsh: axl -x -f librarian.axl file-1.als

       Librarian object
       The  Librarianobject can be used as a convenient way to create a collection of files or to
       extract some of them.

       Output librarian
       The Librarianobject is a standard object. Its predicate is librarian-p. Without  argument,
       a  librarian is created in output mode. With a string argument, the librarian is opened in
       input mode, with the file name argument. The output mode is used to create a new librarian
       by adding file into it. The input mode is created to read file from the librarian.

       # create a new librarian
       const lbr (Librarian)
       # add a file into it
       lbr:add "file-1.als"
       # write it
       lbr:write "librarian.axl"

       The  addmethod adds a new file into the librarian. The writemethod the full librarian as a
       single file those name is writemethod argument.

       Input librarian
       With an argument, the librarian object is created in input mode. Once created, file can be
       read or extracted. The lengthmethod -- which also work with an output librarian -- returns
       the number of files in the librarian. The exists-ppredicate returns true if the file  name
       argument  exists  in  the librarian. The get-namesmethod returns a vector of file names in
       this librarian. The extractmethod returns an input stream object  for  the  specific  file
       name.

       # open a librarian for reading
       const lbr (Librarian "librarian.axl")
       # get the number of files
       println (lbr:length)
       # extract the first file
       const is (lbr:extract "file-1.als")
       # is is an input stream - dump each line
       while (is:valid-p) (println (is:readln))

       Most  of  the  time,  the  librarian object is used to extract file dynamically. Because a
       librarian is mapped into the memory at the right offset, there is  no  worry  to  use  big
       librarian,  even  for  a  small  file.  Note  that  any  type of file can be used, text or
       binaries.

       File resolver
       The file resolveris a special object used by the interpreter to resolve file path based on
       the  search path. The resolver uses a mixed list of directories and librarian files in its
       search path. When a file path needs to be resolved, the search path  is  scanned  until  a
       matched  is  found.  Because  the  librarian resolution is integrated inside the resolver,
       there is no need to worry about file extraction. That process is done  automatically.  The
       resolver can also be used to perform any kind of file path resolution.

       Resolver object
       The  resolver object is created without argument. The addmethod adds a directory path or a
       librarian file to the resolver. The validmethod checks for the existence of  a  file.  The
       lookupmethod returns an input stream object associated with the object.

       # create a new resolver
       const rslv (Resolver)
       assert true (resolver-p rslv)
       # add the local directory on the search path
       rslv:add "."
       # check if file test.als exists
       # if this is ok - print its  contents
       if (rslv:valid-p "test.als") {
         const is (rslv:lookup "test.als")
         while (is:valid-p) (println (is:readln))
       }

       Thread operations
       The  interpreter  is  a  multi-threaded  engine  with  a  native implementation of objects
       locking. A thread is started with the reserved keyword launch. The execution is  completed
       when all threads have terminated. This means that the master thread (i.e the first thread)
       is suspended until all other threads have completed their execution.

       Starting a thread
       A thread is started with the reserved keyword launch. The form to execute in a  thread  is
       the argument. The simplest thread to execute is the nilthread.

       launch (nil)

       There  exists an alternate mechanism to start a thread with the reserved keyword launchand
       a thread object. Such mechanism is used when using deferred thread object  creation  or  a
       thread generator object known as a thread set.

       Thread object and result
       When a thread terminate, the thread object holds the result of the last executed form. The
       thread object is returned by the launchcommand. The thread-ppredicates returns trueif  the
       object is a thread descriptor.

       const thr (launch (nil))
       println   (thread-p thr) # true

       The  thread  result can be obtained with the help of the resultmethod. Although the result
       can be accessed at any time, the returned value will be niluntil the thread  as  completed
       its execution.

       const thr (launch (nil))
       println   (thr:result)   # nilp

       Although  the  engine will ensure that the result is niluntil the thread has completed its
       execution, it does not mean that it is a reliable approach to test until the result is not
       nil.  The  engine  provides various mechanisms to synchronize a thread and eventually wait
       for its completion.

       Shared objects
       The whole purpose of using  a  multi-threaded  environment  is  to  provide  a  concurrent
       execution  with  some shared variables. Although, several threads can execute concurrently
       without sharing data, the most common situation is that one or more  global  variable  are
       accessed  --  and  even changed -- by one or more threads. Various scenarios are possible.
       For example, a variable is changed by one thread, the other thread just  read  its  value.
       Another  scenario is one read, multiple write, or even more complicated, multiple read and
       multiple write. In any case, the interpreter subsystem must ensure that each  objects  are
       in   a  good  state  when  such  operation  do  occur.The  engine  provides  an  automatic
       synchronization mechanism for global objects, where only one thread can modify an  object,
       but  several thread can read it. This mechanism known as read-write lockingguarantees that
       there is only one writer, but eventually multiple reader. When a thread starts  to  modify
       an  object, no other thread are allowed to read or write this object until the transaction
       has been completed. On the opposite, no thread  is  allowed  to  change  (i.e.  write)  an
       object,  until  all  thread  which  access (i.e. read) the object value have completed the
       transaction. Because a context switch can occur at any time, the object read-write locking
       will ensure a safe protection during each concurrent access.

       Shared protection access
       We  illustrate  the  previous  discussion  with an interesting example and some variations
       around it. Let's consider a form which increase an integer object and another  form  which
       decrease  the  same  integer object. If the integer is initialized to 0, and the two forms
       run in two separate threads, we might  expect  to  see  the  value  bounded  by  the  time
       allocated  for each thread. In other word, this simple example is a very good illustration
       of your machine scheduler.

       # shared variable access
       const var 0
       # increase method
       const incr nil {
         while true (println "increase: " (var:= (+ var 1)))
       }
       # decrease method
       const decr nil {
         while true (println "decrease: " (var:= (- var 1)))
       }
       # start both threads
       launch (decr)
       launch (incr)

       In the previous example, varis initialized to 0. The incrthread  increments  varwhile  the
       decrthread  decrements  var.  Depending  on the operating system, the result stays bounded
       within a certain range. The previous example can be changed by using the main thread or  a
       third thread to print the variable value. The end result is the same, except that there is
       more threads competing for the shared variable.

       # shared variable access
       const var 0
       # incrementer, decrementer and printer
       const incr nil (while true (var:= (+ var 1)))
       const decr nil (while true (var:= (- var 1)))
       const prtv nil (while true (println "value = " var))
       # start all threads
       launch (decr)
       launch (incr)
       launch (prtv)

       Synchronization
       Although, there is an automatic  synchronization  mechanism  for  reading  or  writing  an
       object,  it  is sometimes necessary to control the execution flow. There are basically two
       techniques to do so. First, protect a form from being executed by several threads. Second,
       wait  for one or several threads to complete their task before going to the next execution
       step.

       Form synchronization
       The reserved keyword synccan be used to synchronize a form. When a form, is  synchronized,
       the engine guarantees that only one thread will execute this form.

       const print-message (code mesg) (
         sync {
           errorln "error  : " code
           errorln "message: " mesg
         }
       )

       The  previous  example creates a gamma expression which make sure that both the error code
       and error message are printed in one group, when several threads call it.

       Thread completion
       The other piece  of  synchronization  is  the  thread  completion  indicator.  The  thread
       descriptor  contains a method called waitwhich suspend the calling thread until the thread
       attached to the descriptor has been completed. If the thread  is  already  completed,  the
       method returns immediately.

       # simple flag
       const flag false
       # simple tester
       const ftest (bval) (flag:= bval)
       # run the thread and wait
       const thr (launch (ftest true))
       thr:wait
       assert true flag

       This  example is taken from the test suites. It checks that a boolean variable is set when
       started in a thread. Note the use of the waitmethod to make sure the thread has  completed
       before checking for the flag value. It is also worth to note that waitis one of the method
       which guarantees that a thread result is valid. Another use of the waitmethod can be  made
       with  a  vector  of  thread  descriptors  when  one  wants  to wait until all of them have
       completed.

       # shared vector of threads descriptors
       const thr-group (Vector)
       # wait until all threads in the group are finished
       const wait-all nil (for (thr) (thr-group) (thr:wait))

       Complete example
       We illustrate the previous discussion with a complete example. The idea is  to  perform  a
       matrix  multiplication.  A  thread  is  launched  when  when multiplying one line with one
       column. The result is stored in the thread descriptor. A vector of  thread  descriptor  is
       used to store the result.

       # initialize the shared library
       interp:library "afnix-sys"
       # shared vector of threads descriptors
       const thr-group (Vector)
       # waits until all threads in the group are finished
       const wait-all nil (for (thr) (thr-group) (thr:wait))

       The  group  of threads is represented as a vector. Based on the the previous discussion, a
       simple loop that blocks until all threads are completed is  designed  as  a  simple  gamma
       expression.

       # initializes a matrix with random numbers
       const init-matrix (n) {
         trans i (Integer 0)
         const m (Vector)
         do {
           trans v (m:add (Vector))
           trans j (Integer)
           do {
             v:add (afnix:sys:get-random)
           } (< (j:++) n)
         } (< (i:++) n)
         eval m
       }

       The  matrix initialization is quite straightforward. The matrix is represented as a vector
       of lines. Each line is also a vector of random integer number. It is here  worth  to  note
       that the standard mathmodule provides a native implementation of real matrix.

       # this procedure multiply one line with one column
       const mult-line-column (u v) {
         assert (u:length) (v:length)
         trans result 0
         for (x y) (u v) (result:+= (* x y))
         eval result
       }
       # this procedure multiply two vectors assuming one
       # is a line and one is a column from the matrix
       const mult-matrix (mx my) {
         for (lv) (mx) {
           assert true (vector-p lv)
           for (cv) (my) {
             assert true (vector-p cv)
             thr-group:add (launch (mult-line-column lv cv))
           }
         }
       }

       The  matrix  vector  multiplication  is  at  the  heart  of  the example. Each line-column
       multiplication is started into a thread and the thread object is placed  into  the  thread
       group vector.

       # check for some arguments
       # note the use of errorln method
       if (== 0 (interp:argv:length)) {
         errorln "usage: axi 0607.als size"
         afnix:sys:exit 1
       }
       # get the integer and multiply
       const n (Integer (interp:argv:get 0))
       mult-matrix (init-matrix n) (init-matrix n)
       # wait for all threads to complete
       wait-all
       # make sure we have the right number
       assert (* n n) (thr-group:length)

       The  main  execution  is  started  with  the matrix size as the first argument. Two random
       matrices are then created and the multi-threaded  multiplication  is  launched.  The  main
       thread is blocked until all threads in the thread group are completed.

       Condition variable
       A  condition  variableis  another  mechanism  to  synchronize several threads. A condition
       variable is modeled with the Condvarobject. At construction,  the  condition  variable  is
       initialized  to  false.  A  thread  calling  the waitmethod will block until the condition
       becomes true. The markmethod can be used by a thread to change the state  of  a  condition
       variable  and eventually awake some threads which are blocked on it. The following example
       shows how the main thread blocks until another change the state of the condition.

       # create a condition variable
       const cv (Condvar)
       # this function runs in a thread - does some
       # computation and mark the condition variable
       const do-something nil {
         # do some computation
         ....
         # mark the condition
         cv:mark
       }
       # start some computation in a thread
       launch (do-something)
       # block until the condition is changed
       cv:wait-unlock
       # continue here

       In this example, the condition variable is created at the beginning. The thread is started
       and the main thread blocks until the thread change the state of the condition variable. It
       is important to note the use of the wait-unlockmethod. When the main thread is  re-started
       (after  the  condition variable has been marked), the main thread owns the lock associated
       with the condition variable. The wait-unlockmethod unlocks that lock when the main  thread
       is  restarted.  Note  also that the wait-unlockmethod reset the condition variable. if the
       waitmethod was used instead of wait-unlockthe lock  would  still  be  owned  by  the  main
       thread.  Any  attempt  by other thread to call the mark method would result in the calling
       thread to block until the lock is released.The Condvarclass has several methods which  can
       be  used  to  control  the behavior of the condition variable. Most of them are related to
       lock control. The resetmethod reset the condition variable. The lockand unlockcontrol  the
       condition   variable   locking.   The   mark,   waitand   wait-unlockmethod  controls  the
       synchronization among several threads.

       Function expression
       A lambda expression or a gamma expression can be seen like a function object with no name.
       During the evaluation process, the expression object is evaluated as well as the arguments
       -- from left to right -- and a result is produced  by  applying  those  arguments  to  the
       function object. An expression can be built dynamically as part of the evaluation process.

       (axi) println ((lambda (n) (+n 1)) 1)
       2

       The  difference  between a lambda expression and a gamma expression is only in the nameset
       binding during the evaluation process. The lambda expression nameset is  linked  with  the
       calling  one, while the gamma expression nameset is linked with the top level nameset. The
       use of gamma expression is particularly interesting with recursive  functions  as  it  can
       generate  a significant execution speedup. The previous example will behaves the same with
       a gamma expression.

       (axi) println ((gamma (n) (+n 1)) 1)
       2

       Self reference
       When combining a function expression with recursion, the need for  the  function  to  call
       itself is becoming a problem since that function expression does not have a name. For this
       reason, the writing system provides the reserved keyword selfthat is a  reference  to  the
       function   expression.  We  illustrate  this  capability  with  the  well-known  factorial
       expression written in pure functional style.

       (axi) println ((gamma (n)
           (if (<= n 1) 1 (* n (self (- n 1))))) 5)
       120

       The use of a gamma expression versus a lambda expression is a matter of speed.  Since  the
       gamma  expression  does  not  have  free variables, the symbol resolution is not a concern
       here.

       Closed variables
       One of the writing system characteristic is the treatment of free variables. A variable is
       said  to  be  free if it is not bound in the expression environment or its children at the
       time of the symbol  resolution.  For  example,  the  expression  ((lambda  (n)  (+  n  x))
       1)computes the sum of the argument nwith the free variable x. The evaluation will succeeds
       if xis defined  in  one  of  the  parent  environment.  Actually  this  example  can  also
       illustrates  the  difference  between  a  lambda  expression and a gamma expression. Let's
       consider the following forms.

       trans x 1
       const do-print nil {
         trans x 2
         println ((lambda (n) (+ n x)) 1)
       }

       The gamma expression do-printwill produce 3since it sums the argument nbound  to  1,  with
       the free variable xwhich is defined in the calling environment as 2. Now if we rewrite the
       previous example with a gamma expression the result will  be  one,  since  the  expression
       parent will be the top level environment that defines xas 1.

       trans x 1
       const do-print nil {
         trans x 2
         println ((gamma (n) (+ n x)) 1)
       }

       With  this  example,  it  is  easy  to  see that there is a need to be able to determine a
       particular symbol value during the expression construction. Doing so is called  closing  a
       variable.  Closing  a  variable is a mechanism that binds into the expression a particular
       symbol with a value and such symbol is called a closed variable, since its value is closed
       under  the  current  environment  evaluation.  For  example,  the  previous example can be
       rewritten to close the symbol x.

       trans x 1
       const do-print nil {
         trans x 2
         println ((gamma (n) (x) (+ n x)) 1)
       }

       Note that the list of closed variable  immediately  follow  the  argument  list.  In  this
       particular  case,  the  function do-printwill print 3since xhas been closed with the value
       2has defined in the function do-print.

       Dynamic binding
       Because there is a dynamic binding symbol resolution, it is possible to  have  under  some
       circumstances  a  free  or  closed  variable.  This  kind  of  situation can happen when a
       particular symbol is defined under a condition.

       lambda (n) {
         if (<= n 1) (trans x 1)
         println (+ n x)
       }

       With this example, the symbol xis a free variable if the  argument  nis  greater  than  1.
       While  this  mechanism  can  be  powerful,  extreme caution should be made when using such
       feature.

       Lexical and qualified names
       The basic forms elements are the lexical and qualified names. Lexical and qualified  names
       are  constructed  by  the parser. Although the evaluation process make that lexical object
       transparent, it is possible to manipulate them directly.

       (axi) const sym (protect lex)
       (axi) println   (sym:repr)
       Lexical

       In this example, the protectreserved keyword is  used  to  avoid  the  evaluation  of  the
       lexical  object  named  lex.  Therefore  the symbol symrefers to a lexical object. Since a
       lexical -- and a qualified -- object is a  also  a  literal  object,  the  printlnreserved
       function  will  work and print the object name. In fact, a literal object provides the to-
       stringmethod that returns the string representation of a literal object.

       (axi) const sym (protect lex)
       (axi) println   (sym:to-string)
       lex

       Symbol and argument access
       Each nameset maintains a table of symbols. A symbol is a binding between  a  name  and  an
       object.  Eventually,  the  symbol  carries  the  constflag.  During the lexical evaluation
       process, the lexical object tries to find an object in the nameset hierarchy. Such  object
       can  be  either  a  symbol  or an argument. Again, this process is transparent, but can be
       controlled manually. Both lexical and qualified  named  object  have  the  mapmethod  that
       returns the first object associated in the nameset hierarchy.

       (axi) const obj 0
       (axi) const lex (protect obj)
       (axi) const sym (lex:map)
       (axi) println   (sym:repr)
       Symbol

       A  symbol  is also a literal object, so the to-stringand to-literalmethods will return the
       symbol name. Symbol methods are provided to access or modify the symbol values. It is also
       possible to change the constsymbol flag with the set-constmethod.

       (axi) println (sym:get-const)
       true
       (axi) println (sym:get-object)
       0
       (axi) sym:set-object true
       (axi) println (sym:get-object)
       true

       A  symbol  name  cannot  be modified, since the name must be synchronized with the nameset
       association. On the other hand, a symbol can be explicitly constructed. As any object, the
       =operator  can  be  used to assign a symbol value. The operator will behaves like the set-
       objectmethod.

       (axi) const sym (Symbol "symbol")
       (axi) println sym
       symbol
       (axi) sym:= 0
       (axi) println (eval sym)
       0

       Closure
       As an object, the Closurecan be manipulated outside the  traditional  declarative  way.  A
       closure  is  a special object that holds an argument list, a set of closed variables and a
       form to execute. The mechanic of a closure evaluation has been described earlier. What  we
       are  interested  here  is  the ability to manipulate a closure as an object and eventually
       modify it. Note that by default a closure is constructed as a lambda  expression.  With  a
       boolean  argument  set to true the same result is obtained. With false, a gamma expression
       is created.

       (axi) const f (Closure)
       (axi) println (closure-p f)
       true

       This example creates an empty closure. The default closure is equivalent to  the  trans  f
       nil nil. The same can be obtained with const f (Closure true). For a gamma expression, the
       following forms are equivalent, const f (Closure false)and const f nil nil. Remember  that
       it  is  transand constthat differentiate between a lambda and a gamma expression. Once the
       closure object is defined, the set-formmethod can be used to bind a form.

       # the simple way
       trans f nil (println "hello world")
       # the complex way
       const f    (Closure)
       f:set-form (protect (println "hello world"))

       There are numerous situations  where  it  is  desirable  to  mute  dynamically  a  closure
       expression.  The  simplest one is the closure that mute itself based on some context. With
       the use of self, a new form can be set to the one that  is  executed.  Another  use  is  a
       mechanism  call  advice,  where  some  new  computation  are  inserted  prior  the closure
       execution. Note that appending to a closure can  lead  to  some  strange  results  if  the
       existing closure expression uses returnspecial forms. In a multi-threaded environment, the
       ability to change a closure expression is particularly handy. For example a special thread
       could  be used to monitor some context. When a particular situation develops, that threads
       might trigger some closure expression changes. Note that  changing  a  closure  expression
       does  not  affect the one that is executed. If such change occurs during a recursive call,
       that change is seen only at the next call.