Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
VOL-1(7)		      AFNIX Users Manual		      VOL-1(7)

NAME
       vol-1 - afnix programmer's guide

GETTING	STARTED
       AFNIX  is  a multi-threaded functional engine with dynamic symbol bind-
       ings that supports the object oriented paradigm.	The system features  a
       state  of the art runtime engine	that runs on both 32 and 64 bits plat-
       forms. 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.	Alter-
       natively, 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  in-
       terpreter  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 stan-
       dard 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 hier-
       archy  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 stan-
       dard objects provides support  for  integers,  real  numbers,  strings,
       characters  and boolean.	Various	containers like	list, vector, hash ta-
       ble, 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  fea-
       ture  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 sym-
       bol 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  ob-
       jects 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 compat-
       ibility.	 AFNIX implements a true multi-threaded	engine with  an	 auto-
       matic 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 in-
       side 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 de-
       signed to ease the integration of foreign libraries.

       First contact
       The fundamental syntactic object	is a form. A form is parsed and	 imme-
       diately	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  dis-
       plays the message hello world.

       Hello world
       At  the	interpreter prompt, a form is constructed with the special ob-
       ject 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 interac-
       tively. 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  en-
       gine.  Upon completion, the interpreter prompt is displayed and the in-
       terpreter 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  man-
       ual.

       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 op-
       tion 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 automati-
       cally to	the interpreter	resolver path unless the nopathoption is spec-
       ified.

       Interactive line	editing
       Line editing capabilities is provided when the interpreter is used  in-
       teractively.  Error  messages are displayed in red if the terminal sup-
       ports colors. Various accelerators are bound to the terminal  as	 indi-
       cated 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 in-
       terpreter.

       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  ob-
       ject 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	illus-
       trates 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 load-
       method 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 com-
       piled, 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	 sepa-
       rated  by blank lines or	comments. During the compilation or the	execu-
       tion process, each syntactic object is processed	one after another in a
       single pass. Reserved keywords are an integral part of the writing sys-
       tems. 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 until the	end of
       line are	consumed. 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  representa-
       tion  is	required. To perform this task,	several	native objects,	namely
       Booleanfor boolean objects, Integer, Relatiffor integer numbers,	 Real-
       for  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. Eventu-
       ally, 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 ob-
       ject associated with it.

       Stop and	resume parsing
       The parsing process is stopped in the presence of the acharacter	 (Uni-
       code   U+25C0).	 The   parsing	 operation   is	  resumed   with   the
       a<paragraph>character (Unicode U+25B6). Such mechanism is  useful  when
       dealing with multi line statements. This	mechanism is also a good exam-
       ple 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 in-
       terpreter  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). Evalua-
       tion 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 cre-
       ates 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  as-
       sertkeyword.

       Lambda expression
       A  lambda expressionis another name for a function. The term comes his-
       torically 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  ob-
       ject result is transmitted to the calling form. The use of transvs con-
       stis 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 func-
       tion  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 no-
       tation called the block formnotation with the use of the	{and  }charac-
       ters. 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 nota-
       tion 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 re-
       solve the symbols. In other words, each recursive call  to  a  function
       creates	a new symbol set which is linked with its parent. When the re-
       cursion is becoming deep, so is the path	to traverse from the lower set
       to  the	top  one. There	is also	another	mechanism called gamma expres-
       sionwhich binds only the	function symbol	set to the top level one.  The
       rest  remains  the  same. Using a gamma expression can speedup signifi-
       cantly 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 gam-
       mais 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	 vari-
       ables.  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 cre-
       ated.  In the literature, you might discover a similar mechanism	refer-
       enced as	a closure. A closure is	simply a variable which	is closed  un-
       der  a certain context. When a variable is reference in a context with-
       out any definition, such	variable is called a free  variable.  We  will
       see  later more programs	with closures. Note that it is the object cre-
       ated 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 argu-
       ments using the special argsbinding. During a lambda or	gamma  expres-
       sion  execution,	the special symbol argsis defined with the extra argu-
       ments 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	 args-
       formal  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	 vari-
       able.  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 com-
       mon  properties,	 like being settable. Another point to note is the na-
       ture 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 al-
       ways  in	 terms of namesets, no matter how it is	implemented. All name-
       sets 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 ob-
       ject. 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 vari-
       ous  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 ex-
       ample, the qualified name .:hellorefers to the symbol helloin the  cur-
       rent  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	situa-
       tions can occur.	If the symbol is found,	it is set with the correspond-
       ing 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 en-
       couraged	-- 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 ex-
       pression	is constructed from the	argument list and bounded to the spec-
       ified 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	const-
       works 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 con-
       text. When the context is a nameset, the	 object	 associated  with  the
       symbol  is detached from	the symbol, eventually destroyed with the sym-
       bol 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	 argu-
       ment 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 expres-
       sion  evaluation	 with  the  remaining arguments	passed at the time the
       call is made. The symbol	can be either nilor bound to  a	 list  of  ob-
       jects.

       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	 argu-
       ment is evaluated or nil	is returned if it does not exist. An interest-
       ing 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 bool-
       ean.  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 ini-
       tialization  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 syn-
       tax  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	 argu-
       ments.  The first is the	initialize form. The second is the exit	condi-
       tion. 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  cre-
       ates 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  af-
       ter 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 else-
       can 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	termi-
       nates.  If  returnis  used  at the top level, the result	is simply dis-
       carded.

       # 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 re-
       turn. The protectreserved keyword constructs an object without evaluat-
       ing 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  key-
       word 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 log-
       ical operations are also	integrated in the writing  system.  The	 Inte-
       gerand  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 de-
       scribed in the next chapter.

       Arithmetic operations
       Support for the arithmetic operations is	provided with the standard op-
       erator 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 sym-
       bols. 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 al-
       ways a built-in predicate associated with a built-in object. By conven-
       tion,  a	 predicate terminates with the sequence	-p. The	nil-ppredicate
       is a special predicate which returns true if the	object is nil. The ob-
       ject-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 cre-
       ated 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	execu-
       tion process.

       Class and members
       A  class	is declared with the reserved keyword class. The resulting ob-
       ject 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 qual-
       ified 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  initial-
       ize 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 expres-
       sion is bound to	the class. Since presetis  a  reserved	name  for  the
       class  object,  the form	is automatically executed at the instance con-
       struction. 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 thi-
       sis not recommended in a	gamma expression, although it is perfectly ac-
       ceptable	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	itera-
       tion, 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 cur-
       rent iterator position.

       Exception
       An exceptionis an unexpected change in the execution flow.  The	excep-
       tion  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 un-
       less 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  han-
       dler  and  eventually  retrieve some information	from the exception ob-
       ject. 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:about-
       contains	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 cer-
       tain text patterns. Regular expressions are  built  implicitly  by  the
       parser  with  the use of	the [and ]characters. Special class of charac-
       ters are	defined	with the help of the $character. For example, $dis the
       class of	character digits as defined by the Unicode consortium. Differ-
       ent regular expression can be grouped by	region to be matched as	 indi-
       cated 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 ==re-
       turns  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 concur-
       rent 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 cre-
       ated 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 imme-
       diately.

       # 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 char-
       acter 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	repre-
       sentation. 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  Integerob-
       ject 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 construc-
       tors. 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	 prop-
       erty 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 argu-
       ments. 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 follow-
       ing 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	recur-
       sion. 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  be-
       tween  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-string-
       method  returns a string	representation of the calling integer, the to-
       literalmethod returns a parsable	string.	Strictly speaking for an inte-
       ger,  there is no difference between a string representation and	a lit-
       eral 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 hexa-
       decimal	format.	 The  to-hexaand to-hexa-strignmethods are designed to
       obtained	such representation. In	the first form,	the to-hexamethod  re-
       turn  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  Re-
       latifclass is similar to	the Integerclass except	that it	works with in-
       finitely	long number. The relatif notation uses a ror  Rsuffix  to  ex-
       press  a	 relatif  number versus	an integer one.	The Relatifobject is a
       literal object that belongs to the number class.	The predicate  associ-
       ated 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 ex-
       ponent 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 op-
       erations	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 num-
       ber. 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 re-
       sult.

       + 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 op-
       erators,	 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 or-
       der 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 num-
       bers. With integers, you	might get some strange results anyway, but  it
       will work. Note also how	the closed variable mechanism is used. The re-
       cursion 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 in-
       clude the trigonometric functions, the logarithm	and couple others. Hy-
       perbolic	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 na-
       ture 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-abso-
       lute-precisionreturns  the  interpreter precision. There	is also	a set-
       relative-precisionand get-relative-precisionmethods used	for the	 defi-
       nition 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  pre-
       cision  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-right-
       methods 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  Numberob-
       ject  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-hex-
       aand  to-hexa-stringmethods.  For integer and real numbers, the format-
       method adjusts the final	representation with the	precision argument  as
       indicated before. It is worth to	note that a formatted integer gets au-
       tomatically converted into a real representation.

       Character
       The Characterobject is another built-in object. A character  is	inter-
       nally  represented by a quad by using a 31 bit representation as	speci-
       fied 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  en-
       gine.  The  characters  are constructed from the	literal	notation or by
       using an	explicit character instance. The Characterclass	 offers	 stan-
       dard  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 nota-
       tion based on the U+notation in hexadecimal. For	 example,  U+40is  the
       @character while	U+3A3is	the sigma capital letter IL.

       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  in-
       teger  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	opera-
       tions 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 argu-
       ments.

       == '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 al-
       pha-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 con-
       structor	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 com-
       mon  ones  are  illustrated in the example below. The lengthmethods re-
       turns the total number of characters in the string object. It is	 worth
       to note that this number	is not necessarily the number of printed char-
       acters since some characters might be combining charactersused, for ex-
       ample,  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	 posi-
       tion  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 ac-
       cording 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-lowermeth-
       ods.  The  method operates with the internal Unicode database. As a re-
       sult, 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 xor-
       ingthe 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	match-
       ing 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	delim-
       iters.  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 con-
       struction 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 al-
       phanumeric 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  im-
       plicit  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, con-
       trol 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  suc-
       cessful.	 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 argu-
       ment 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 specifi-
       cally, iterableobjects such like	Cons, Listand Vector. Special  objects
       like  Fifo,  Queueand Bitsetare treated at the end of this chapter. Al-
       though the name container is sufficient enough to describe  the	object
       functionality,  it  is clear that a container is	more than a simple ob-
       ject reservoir. In particular, the choice of a container	object is  of-
       ten  associated	to  the	underlying algorithm used to store the object.
       For example, a vector is	appropriate when storing by  index  is	impor-
       tant.  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	tradi-
       tional functional programming language. A Consobject is a  simple  ele-
       ment  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 Listob-
       ject  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. Un-
       like 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  Vectorob-
       ject provides support for forward and backward iteration.

       Vector construction
       A  vector  is  constructed like a cons cell or a	list. The default con-
       structor	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	Setob-
       ject is another example of iterable object. The Setobject provides sup-
       port 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 ob-
       ject  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 asso-
       ciated 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 re-
       turns 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	itera-
       tion.  The  beginmethod	reset  the iterator to the beginning. The end-
       method 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 mem-
       bers. 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 con-
       struction 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 in-
       stance of that class. When the data member is declared  with  the  con-
       streserved 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 eval-
       uate 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 in-
       stance 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  in-
       stance  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  ex-
       pression	 called	 preset. This lambda expression, if it exists, is exe-
       cuted after the default instance	has been constructed. Such lambda  ex-
       pression	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 ob-
       ject is created.	The constructor	is invoked with	the  thissymbol	 bound
       to the newly created instance. Note that	the qualified name this:redde-
       fines a new symbol in the instance nameset. Such	 symbol	 is  sometimes
       referred	 as an instance	data member. Note as well that there is	no am-
       biguity 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  in-
       stance 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	there-
       fore 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 initializa-
       tion 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	 name-
       set.  If	 the  instance method is defined in the	class nameset, the in-
       stance 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  al-
       ways 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.	Opera-
       tors like ==or !=generally requires the ability to assert if the	 argu-
       ment  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  metasym-
       bol, 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 op-
       erators.	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 Realob-
       ject 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  re-
       turned 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-compari-
       son 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 op-
       erator creates a	copy for both the real and imaginary part. The	summa-
       tion 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 uti-
       lization	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 ob-
       ject 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  mem-
       ber.  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  en-
       gine  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  in-
       stance  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  preset-
       method 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  in-
       ferred 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 asso-
       ciated  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 proper-
       ties 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	excep-
       tion 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	excep-
       tion  is	thrown,	the normal flow	of execution is	interrupted and	an ob-
       ject used to carry the exception	information is created.	Such exception
       object is propagated backward in	the call stack until an	exception han-
       dler 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	excep-
       tion 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 argu-
       ment, 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	inter-
       esting  results are obtained. Because symbols are resolved in the name-
       set 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	mecha-
       nism  permits the encapsulation of a form to be evaluated inside	an ob-
       ject called a promise.

       Creating	a promise
       The reserved keyword delaycreates a promise. When the promise  is  cre-
       ated, the associated object is not evaluated. This means	that the prom-
       ise 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  de-
       clared  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,  enu-
       meration	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	gener-
       ally indicates a	warning	or an error message but	this is	just a conven-
       tion  which  is not enforced by the class. A high level generally indi-
       cates 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  length-
       method returns the number of logged messages. The get-messagemethod re-
       turns 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 mes-
       sage. The get-message-levelreturns the message level and	 the  get-mes-
       sage-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	inter-
       preter 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
       program-name		Interpreter program name
       major-version		Major version number
       minor-version		Minor version number
       patch-version		Patch version number
       afnix-uri		Official uri name
       load			Load a file and	execute	it
       launch			Launch a normal	thread
       library			Load and initialize a library
       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:versionquali-
       fied  name.  The	full version is	composed of the	major, minorand	patch-
       number. The operating system name is bound to the  qualified  name  in-
       terp: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

       File loading
       The  interp:loadmethod loads and	execute	a file.	The interpreter	inter-
       active 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 re-
       solver. Without extension, a compiled file is searched first and	if not
       found a source file is searched.

       Library loading
       The interp:librarymethod	loads and initializes a	 library.  The	inter-
       preter  maintains  a list of opened library. Multiple execution of this
       method for the same library does	nothing. The method  returns  the  li-
       brary object.

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

       Interpreter duplication
       The interpreter can be duplicated with the help of the dupmethod. With-
       out 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  dup-
       method also accepts a terminal object.

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

       Interpreter loop
       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	conve-
       nient 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

       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 in-
       terpreter 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	speci-
       fied 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 li-
       brarian.

       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 collec-
       tion 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 ar-
       gument.	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  librar-
       ian.

       # 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 li-
       brarian.	 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 ob-
       ject 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  dynami-
       cally.  Because a librarian is mapped into the memory at	the right off-
       set, 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 re-
       solver, 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 exe-
       cute 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 ap-
       proach to test until the	result is not nil. The engine provides various
       mechanisms  to synchronize a thread and eventually wait for its comple-
       tion.

       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 synchro-
       nization	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 eventu-
       ally  multiple  reader.	When  a	 thread	starts to modify an object, no
       other thread are	allowed	to read	or write this object until the	trans-
       action  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 con-
       text 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  in-
       teger  object  and another form which decrease the same integer object.
       If the integer is initialized to	0, and the two forms run in two	 sepa-
       rate  threads, we might expect to see the value bounded by the time al-
       located 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	incre-
       ments varwhile the decrthread decrements	var. Depending on the  operat-
       ing system, the result stays bounded within a certain range. The	previ-
       ous 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	execu-
       tion 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	execu-
       tion 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 imme-
       diately.

       # 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	 wait-
       method  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 pre-
       vious discussion, a simple loop that blocks until all threads are  com-
       pleted 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 rep-
       resented	as a vector of lines. Each line	is also	a vector of random in-
       teger  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 ob-
       ject 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	 argu-
       ment.  Two random matrices are then created and the multi-threaded mul-
       tiplication 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	condi-
       tion variable. Most of them are related to  lock	 control.  The	reset-
       method reset the	condition variable. The	lockand	unlockcontrol the con-
       dition 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  ob-
       ject is evaluated as well as the	arguments -- from left to right	-- and
       a result	is produced by applying	those arguments	to  the	 function  ob-
       ject.  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  ex-
       pression	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 ex-
       pression	does not have a	name. For this reason, the writing system pro-
       vides  the reserved keyword selfthat is a reference to the function ex-
       pression. 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 vari-
       ables. A	variable is said to be free if it is not bound in the  expres-
       sion  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	mecha-
       nism  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 ex-
       ample 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	condi-
       tion.

       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 evalua-
       tion  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 eval-
       uation  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 be-
       tween a name and	an object. Eventually, the symbol carries  the	const-
       flag.  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 hier-
       archy.

       (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-literalmeth-
       ods  will return	the symbol name. Symbol	methods	are provided to	access
       or modify the symbol values. It is also possible	to change  the	const-
       symbol 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  ex-
       plicitly	 constructed.  As any object, the =operator can	be used	to as-
       sign a symbol value. The	operator will  behaves	like  the  set-object-
       method.

       (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 ob-
       tained. 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  equiva-
       lent  to	 the  trans  f	nil nil. The same can be obtained with const f
       (Closure	true). For a gamma expression, the following forms are equiva-
       lent,  const  f (Closure	false)and const	f nil nil. Remember that it is
       transand	constthat differentiate	between	a lambda and a	gamma  expres-
       sion.  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 ex-
       isting 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  con-
       text.  When a particular	situation develops, that threads might trigger
       some closure expression changes.	Note that changing a  closure  expres-
       sion  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.

AFNIX				  2017-04-29			      VOL-1(7)

NAME | GETTING STARTED | LITERALS | CONTAINER OBJECTS | CLASSES | ADVANCED CONCEPTS

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=afnix::guide&sektion=7&manpath=FreeBSD+12.1-RELEASE+and+Ports>

home | help