module Intro: sig end
For a more comprehensive documentation, a list of examples, and an
exposition of the MGS motivations and background, please visit the
URL http://mgs.lami.univ-evry.fr
. This chapter is only a survival
guide and does not cover the specificities of the MGS
language. Refer to the chapter Collections
and Functional
for a
presentation of the core concepts of MGS.
MGS is a untyped functionnal language that enables the case-based definition of functions on collections. These functions are called transformation. The language includes also imperatives features like globale variables.
A collection is an aggregate of values structured by topological
relationships. See the chapter Collections
in this documentation
for more details about topological collections. See the chapter
Functional
for more details about the notion of transformations.
The top-level read-eval-print loop:
The MGS interpreter reads its input, parses the stream of characters
to recognize an expression, evaluates the expression and prints the
result. To force the end of an expression, one may use the
terminator ;;
(the double semi-column). In this manual pages, we
often omit the terminator and the examples of expression must be
completed by the ;;
. In addition, when using the interpreter on a
standard unix terminal, the input are buffered (by unix) and a final
carriage-return must be entered to complete the input.
The top-level accepts expression and also commands. Commands
are order directed to the interpreter and are not part of the MGS
programming language. Commands always begin with a !
. Type the
command
!help;;
at the top level to have a list of the available commands.
Identifier:
identifiers come in simple or quoted form. A quoted
from is a string of characters that begins with a quote '
. Quoted
identifiers are predefined variables. The value of a quoted
identifier cannot be changed. A simple identifier is a string of
characters that does not begin with a quote. Simple identifier can
be used by the programmer as the name of a global variable, as the
name of a function parameter or as the name of a variable introduced
by a let.
The quote of a quoted name can often be omitted. Indeed, when a
simple identifier is encountered, the evaluation process looks first
if a value is attached to this identifier. If not, the evaluation
process looks if the corresponding quoted name is defined. So
expression sin(0.77)
is interpreted as 'sin(0.77)
until the
variable sin
is defined. When this variable is defined, it is
still possible to access the sin function using the (full) quoted
name 'sin
.
Global and let variables and their imperative assignation: Some identifiers refer to an imperative variable. Such variables are global to the program or visible only in a scope introduced by a let construct.
The :=
operator is used to change the value of a global variable:
a := 3
links the variable identified by a
to the value 3
until the next
affectation. The reference to a global variable that has not been
previously affected returns a special value called <undef>
. The
evaluation of the expression:
an_identifier_not_previously_used;;
returns <undef: uninitialized var: an_identifier_not_previously_used >
.
In contrary to the usual handling of let variables in
functional languages, the variables introduced by a let can be
assigned in MGS. For example:
let x = 1 in x:=x+2
is a valid expression that returns 3
. The same let can be used to
introduce several local variables:
let x = 1 and y = 2 in x+y
The scoping rules are the standard ones: the variable x
introduced
by the let is not usable in the expression defining the value of y
and both x
and y
are unknown outside the in
clause.
Functions:
Function are first-class value that can be given as argument to
another function or returned as the value of a function application.
Functions are defined in a syntax similar to the
usual lambda-calculus. For example, \x.x
defines the identity
function. The application of a function to its argument needs
parenthesis:
(\x.x)(3)
denotes the application of the identity to the argument 3.
All functions in MGS are curryfied. However, there are some
shortcuts to make the notation more lighter: \x.\y.x(y)
can be simplified in
\x,y.x(y)
In the same spirit, the application of a function f
to two (or
more) arguments can be written
f(1,2, ...)
instead of the more heavier f(2)(3)...
. Beware that the
comma is also the name of an infix operator used to build
sequence. For example 1, 2, 3
is an expression that builds a
sequence of 3 elements. In function application, the comma is
interpreted in favor of the application to multiple arguments. To
force the application of a function to a sequence build with the
comma operator, parenthesis can be used:
f(1, 2, 3)
denotes the application of function f
to three arguments while:
g((1, 2, 3))
denotes the application of the function g
to one argument which is
an expression that build a sequence, and
h((1, 2, 3), 4)
denotes the application of the function h
to two arguments (the
first is a list and the second is the integer 4
).
To give a name to a function, we can use the let construct that binds locally an identifier to a value, or the assignment that changes the value linked to a global imperative variable. For example
let id = \x.x in (id(id))(3)
returns 3
because id(id)
is equivalent in the scope of the let,
to the expression (\x.x)(\x.x)
which evaluates to the identity
function. Outside the in
clause, the identifier id
is unknown.
The :=
operator can used to give a global name to a function:
id := \x.x
links the identity function to the identifier id
until the next
assignment. There is a short-cut used to define a function and
simultaneously to link it to a global identifier:
fun id(x) = x
is equivalent to
id := \x.x
The shortcut for the handling of multiple arguments is also
provided:
fun f(x, y, z) = x + y*z
A function defined with the fun
construct is called a named
function by opposition with anonymous function defined using the
lambda-notation. There is a special feature linked with the use of
fun
to define a function: such function can have optional arguments.
Predefined functions, i.e. functions that are "magically" defined
when one enters the MGS top-level, have all a quoted name that
cannot be redefined. For example, fun 'f(x) = x
, 'f := ...
or
let 'f = ...
are incorrect expressions and are rejected (at the
parsing phase).
Some predefined functions have a special infix syntax, like the
operator +
: the syntax
1+2
is an alias for the expression
'add(1, 2)
There is another way to define functions:
transformation. Visit the Functional
chapter for a
description of transformations.
Recursion: The name of a named function can be used in the definition of this function. This allows the direct expression of the recursion. For example:
fun fact(x) = if x < 1 then 1 else x*fact(x-1) fi
defines the standard factorial function.
Variable capture and imperative feature:
The partial application of the anonymous function \x,y.x+y
to the
argument 1
returns a function that can be used to compute the
successor
let succ = (\x,y.x+y)(1) in succ(2)
returns 3
. It is customary to say that the argument x
that refers
to the value 1
is captured in the function \y.x+y
and the result
is a cloture, i.e. a function with an environment that binds some
variables.
In contrary to the usual handling of let variable in functional languages, in MGS the variable introduced by a let can be assigned. In conjonction with the capture of variables, this features enables intersting behaviors. For example:
f := let x = 1 in \z.x:=x+z
is a valid expression. The global variable f
is linked to a
cloture that embeeds the let variable x
. Each time the
function f
is called, the store associated to x
is updated. So
f(10)
returns the value 11
and a consecutive call f(10)
returns
21
.
Optional arguments of a named function: not yet described
Iteration of the function application: not yet described
Tracing a function: the call to a named function f
can be
traced using the command !trace f
or the expression trace("f")
(this function takes a string as argument. The command !untrace f
or
the function untrace("f")
can be used to cancel the trace of
f
. See the function the definition of the function trace
in the
System
chapter. Only named function can be traced, however this
includes predefined functions.
Switch statement: the keyword switch
can be used to avoid a
lot of nested if ... then ... else ... fi
constructions. The use
of switch
looks very similar as its equivalent construction in C:
switch exp
case scl_1 : exp_1
...
case scl_n : exp_n
default : exp_d
endswitch
compares the evaluation of the expression exp
with each scalar
scli
in the order given the user, and returns the evaluation of
the associated expression exp_i
. If no scl_i
matches with exp
the default
expression exp_d
is evaluated and returned. The
default
case is optional ; the returned default value is
<undef: macro: make_switch: switch default case>
The expression exp
is evaluated only one time, at the beginning
of the evaluation of the switch
construction. In fact, a switch
is a syntactic sugar for:
let new_id = exp in
if (new_id == scl_1) then exp_1
else if ...
else if (new_id == scl_n) then exp_n
else exp_d fi ... fi fi
Exception handling: the structures raise ...
and try ...
with ...
allows the use of exceptions in MGS. The syntax looks
like the Ocaml one.
To raise an exception, the keywords raise
has to be used as
following:
raise `symbol
The exception is identified by an MGS symbol (see the chapter
Scalar
for details), here `symbol
. A sequence of arguments can
be associated with these exceptions:
raise (`symbol arg_1, arg_2, ...)
where parentheses can be added around the arguments.
These exceptions can be caught using a try ... with ...
structure :
try exp
with
| `symbol1 (arg1_1, ...) -> exp_1
| `symbol2 (arg2_1, ...) -> exp_2
...
where the first pipe is optional. If the expression exp
raises
an exception, the exception value is
matched against the list `symbol1, `symbol2, ...
. If the raised
exception corresponds to `symbol_i
, exp_i
is evaluated where the
free variables arg_1, ...
are replaced by the arguments of the
exception. Note the number of arguments has to matched for an
exception to be caught. For example :
try
raise (`S 1,2,3)
with
| `S (x,y) -> x*y
| `S (x,y,z) -> x+y+z ;;
returns 6
.
The rest of the online-documentation: the on-line documentation is divided in several chapters:
Intro
is this short introduction to MGS.System
describes the system-related functions: input/output,
process spawning, etc.Collections
introduces the notions of collections in MGS. In
this chapter, only the overall structure of the collections types is
described, as well as generic functions that can handle any
collection types. Each specific type of collection are described in
a dedicated chapter.Scalar
covers the scalar types and the related
functions. Scalar type corresponds to indecomposable values. Example
of scalar type are integer, boolean or function.Math
lists the arithmetic operators and the mathematical
constants and functionsFunctional
introduces some functional constants and the
specification of transformations, which are a special kind of
functions that act on collections.Record
describes the record collection type.Monoidal
describes the set, multiset and sequence collection
types. GBF
describes collections defined by a uniform
neighborhood. Arrays are a special kind of GBF. Graph
describes the graph collection type.Delaunay
describes the delaunay collection type. Chain
describes the (forthcoming) abstract chain complex collection type.