Module Intro


module Intro: sig  end
A very short introduction to MGS.

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: