A quick introduction to |
This document is a tutorial introduction to the
Identifiers of variables are formed using letters, digits and the special characters _ and ?. Identifiers must start with a letter or _. Identifiers should match the regular expression [a-zA-Z_]+[a-zA-Z0-9_?]*.
To assign a value to a variable, we use the operator := :
Mmx] |
a1 := 1 |
Constant values can be assigned by the operator ==, and cannot be modified hereafter:
Mmx] |
a1_? == 2; a1_? |
The operator == will be used for instance to define functions which definition should not be modified.
Mmx] |
cst: Int == 11111*111111 |
:
Mmx] |
mut: Int := 1010*1234 |
:
Below, we try to modify a constant and we get an error:
Mmx] |
cst := - cst |
cst := - cst
~~~
:
:
,
whereas modifying a variable is not a problem:
Mmx] |
mut := - mut |
:
Mmx] |
In this section, we describe the basic types, which exist by default in the interpreter. For the other types provided by the extension packages, see their documentation.
The default type of an object is Generic and the corresponding variable type is Alias Generic:
Mmx] |
a := x |
Mmx] |
type a |
Mmx] |
The usual boolean constant are true and false. The equality and inequality tests are = and !=.
Mmx] |
a = a |
Mmx] |
a != a |
To build boolean expression, we use the operators and, or and the negation operator ! :
Mmx] |
a = b and a != c |
Mmx] |
a = b or a != c |
Mmx] |
!( a = b or a != c) |
Constants, functions or operators with an argument of type Boolean in its signature:
Mmx] |
help Boolean |
Available functions
Mmx] |
Strings can be braced into double quotes " … ". Inside such a string a double quote must be blackslashed. In order to avoid blackslashing one can use the stronger string delimiters /" … "/.
Mmx] |
s1 := "This is a string" |
Mmx] |
s2 : String := "Print \"foo\" " |
Not that in this definition, we specify that the variable s2 is of type String.
Mmx] |
s2 := /" Print "foo" "/ |
The concatenation of strings can be done by the operator ><
Mmx] |
s3 := s2 ><" and \"fii\" " |
It is also possible to use the in place concatenation operator << on a variable:
Mmx] |
s2 <</" and "fuu" "/ |
The length of a string is given by the operator #
Mmx] |
#s1 |
Search forward the position of a substring. If it is not found,
the result is , otherwise it returns the
position of the first character.
Mmx] |
search_forwards (s2, "Print", 0) |
Mmx] |
replace(s2, "fuu", "haha") |
Constants, functions or operators, with an argument of type String in its signature:
Mmx] |
help String |
Available functions
Mmx] |
An integer literal is a sequence of digits, possible preceded by a minus sign. It matches the regular expression [-]?[0-9]+. Examples: 123456789123456789, -123.
Mmx] |
a := 2 |
The usual arithmetic operators +, -, * are available:
Mmx] |
a+3; a-5; a*a |
as well as the inplace operators +=, -=, *= :
Mmx] |
a += 1; a *= 2; a -= 3 |
Mmx] |
5 div 2 |
Mmx] |
5 mod 2 |
The default type for integers is Int. It corresponds to machine type int.
Mmx] |
type(1) |
Constants, functions or operators, with an argument of type Int in its signature:
Mmx] |
help Int |
Available functions
By default, the floating point literals are converted to Double types. A floating literal is a sequence of digits with a decimal point inside and an optional exponent. It matches the regular expression [-]?[0-9]+[.][0-9]+[[eE][-]?[0-9]+]?.
Note that 0. is not permitted, one must write 0.0;
Mmx] |
2.1 |
Mmx] |
2.1*3 |
Mmx] |
2.3/2-1 |
Mmx] |
type(1.1) |
Mmx] |
help Double |
Available functions
In order to have access to extended arithmetic
(Integer, Rational, Floating,…), one can use
the package numerix. In this case, the
integer literals will yield numbers of type Integer,
based on
Mmx] |
use "numerix"; type(1) |
For more details on the package numerix, see here.
Mmx] |
The Syntactic type can be used to produce document outputs, represented as lisp-type expressions. It is automatically parsed by TeXmacs to display these outputs.
Mmx] |
type_mode?:=true |
:
Mmx] |
'x |
:
Mmx] |
'(f (x, y, z)) |
:
Mmx] |
'(f (x, y, z)) [2] |
:
Mmx] |
$document ("Some ", $with ("color", "red", "red"), " text."; "Pythagoras said ", $math ('(a^2 + b^2 = c^2)), ".") |
: .
Mmx] |
Vectors are sequence of elements, stored in an array and with a direct access through their index. Their type is parametrized by the type of the elements. The default type is Vector Generic.
Mmx] |
v := [1,2,3] |
The indices start from 0 :
Mmx] |
v[0]+v[1]+v[2] |
The length of a vector is given by the prefix operator #:
Mmx] |
#v |
The concatenation of vectors is performed by the operator ><:
Mmx] |
w := v >< [4,5] |
The inplace concatenation of vectors is done by the operator <<:
Mmx] |
v << [1,2] |
The classical operations car, cdr, cons on lists are available also on vectors:
Mmx] |
[car(v), cdr(v), cons(3,v)] |
Mmx] |
reverse v |
Mmx] |
contains?(v,1) |
Mmx] |
help Vector(Generic) |
Available functions
Mmx] |
Tuples are written inside (…). Elements are separated by ,.
Mmx] |
v := (1,2,3) |
Note the associativity of tuples:
Mmx] |
(1,(2,3)) |
Mmx] |
v:= [1,2]; (v,((v))) |
Mmx] |
help Tuple(Generic) |
Available functions
Mmx] |
a to b means the range [a,b], while a..b stands for the half open range [a,b).
Mmx] |
(1 to 4) |
Mmx] |
1 .. 4 |
Note that 1..4 or 1 to 4 are not tuples but iterators, that can be used to produce sequences:
Mmx] |
[1..6] |
Mmx] |
[i*i | i in 1 to 10] |
Double iterators are also possible when matrix types are available:
Mmx] |
use "algebramix"; [i+j | i in 0 to 9 || j in 0..10] |
Mmx] |
Tables allow to store the association between keys of one type and values of another type. They are defined by providing a default value. In the following example, the default value is 1:
Mmx] |
t := table(1); |
Mmx] |
t[1] := -3; t[34] := 2 |
Mmx] |
t[0] |
Mmx] |
contains? (t,2) |
Mmx] |
help Table(Generic,Generic) |
Available functions
Mmx] |
The default type for tables used in the interpreter is Table(Generic,Generic).
The condition construction is as follows:
if condition then block1 [else block2]
where condition is any expression that evaluates to a boolean. block1 and block2 are either one instruction or a block of instructions braced into {…}. The […] (here the else part) means that the expression is optional.
Mmx] |
if true then 1 |
:
Mmx] |
if a = b then 1 else 2 |
:
Mmx] |
if i = 0 then { x := 1; y := 2 } else { z := 3; mmerr << "error" } |
:
Mmx] |
Loops are constructed as follows:
[for E1] [while E2] [until E3] [step E4] do block
The block is an instruction or a sequence of instructions delimited by {…}. break exits the loop, and continue goes to the next step of the loop.
Mmx] | for i in 1..3 do mmout << i << " "; |
1 2
Mmx] | i := 0; while i < 5 do { mmout << i << " "; i := i + 1 } |
0 1 2 3 4
Mmx] |
// do mmout << "no end "; // This loop has no end |
A function definition is done as follows:
name (arg1: type1, arg2: type2, …): returned_type == block
The block is either one instruction or several
instructions in between { }.
lambda (arg1: type1, arg2: type2, …): returned_type do …
Notice that any of the type specifications can be omitted, in which case the type is assumed to be Generic.
Mmx] |
f (x: String) :String == return x><x |
:
Mmx] |
f("ab") |
:
A function is called in the usual way: foo(arg1, arg2,…).
If foo is unitary then () can be omitted, but note that foo a b c is equivalent to foo(a(b(c))). Function call is always by value.
In the following definition, no type are specified so that the input and output type Generic are assumed:
Mmx] |
f (x) == { a :Generic == x*x; return a } |
:
When a function has only one argument, the parenthesis () can be omitted.
Mmx] |
f 3.1 |
:
The same name f is used for the definition of two
functions of types lambda: Int
Int, lambda: Generic
Generic. The polymorphism of f is resolved by
the type of its argument:
Mmx] |
f "xx " |
:
Mmx] |
f 2.1 |
:
Local variables have to be declared with a type and an initial value:
Mmx] |
add_naive (a: Vector Generic) == { c : Generic := 0; for x in a do c := c + x; return c; } |
:
Mmx] |
add_naive([1,2,3]) |
:
The definition of a postfix function is preceded by the keyword postfix. The name of the function should start with a .:
Mmx] |
postfix .sq(i : Int) : Int == { return i*i } |
:
Mmx] |
3.sq |
:
Mmx] |
postfix .m (a: Int) (b: Int) : Double == { return 1.0*a*b } |
:
Mmx] |
3.m(3) |
:
Mmx] |
fib (n: Int): Int == if n <= 1 then 1 else fib (n-1) + fib (n-2) |
:
Mmx] |
[fib n | n in 1..10] |
:
Mmx] |
shift (x: Int) (y: Int): Int == x + y |
:
Mmx] |
shift 3 |
:
Mmx] |
(shift 3) 4 |
:
Mmx] |
map (shift 3, [ 1 to 20 ]) |
:
Mmx] |
Any function definition can be preceded by quantifiers forall(…) or exists(…).
forall (R) gcd (p: Polynomial(R), q: Polynomial(R)): Polynomial(R) == {…}
Mmx] |
risky (x: Int): Double == { if x = 5 then raise "not in domain"; return 1 / (x - 5); } try { for i in 1 to 10 do mmout << i << " -> " << risky i << "\n"; catch (err: String) { mmout << "error: " << err << "\n"; } }; |
->
->
->
->
-> error: not in domain
Mmx] |
A macro corresponds to a syntactic definition. No type is needed:
Mmx] |
square x ==> x*x |
:
Mmx] |
square 2.1 |
:
Mmx] |
square 2 |
:
Mmx] |
disc(a,b,c) ==> b*b - 4*a*c |
:
Mmx] |
disc (1,2,3.001) |
:
Macros can be usefull to define short and convenient names for types for instance:
Mmx] |
VG ==> Vector Generic |
:
Mmx] |
f(a : VG) == car a |
:
Mmx] |
f ([1,2]) |
:
Mmx] |
Mmx] |
class Color == { mutable { r: Double; g: Double; b: Double; } constructor grey (x: Double) == { r == x; g == x; b == x; } constructor rgb (r2: Double, g2: Double, b2: Double) == { r == r2; g == g2; b == b2; } } |
Mmx] |
rgb (1, 0, 0) |
:
Mmx] |
flatten (c: Color): Syntactic == syntactic ('rgb (as_generic flatten c.r, as_generic flatten c.g, as_generic flatten c.b)); |
Mmx] |
rgb (1, 0, 0) |
:
Mmx] |
mix (c1: Color, c2: Color, a: Double): Color == rgb (a * c1.r + (1-a) * c2.r, a * c1.g + (1-a) * c2.g, a * c1.b + (1-a) * c2.b); |
Mmx] |
mix (rgb (1, 0, 0), grey (0.5), 0.5) |
:
Mmx] |
The operator :> can be used to convert a given type to another, provided that the corresponding function downgrade is defined. We show here an example of an explicit conversion from a class Alpha_color to the class Color:
Mmx] |
class Alpha_color == { mutable { c: Color; a: Double; } constructor alpha_color (c2: Color, a2: Double) == { c == c2; a == a2; } }; |
Mmx] |
alpha_color (rgb(0,0,1), 0.5) |
:
Mmx] |
downgrade (ac: Alpha_color): Color == mix (ac.c, rgb(1,1,1), ac.a); |
Mmx] |
alpha_color (rgb(0,0,0), 0.6) :> Color |
:
In order to define implicit conversions from a type to another, one can use the function updgrade:
Mmx] |
upgrade (x: Double): Color == grey x; |
We use implicitely in the instruction below to convert 1.0 to a Color type:
Mmx] |
mix (1.0, rgb (0, 1, 0), 0.2) |
:
Mmx] |
mix (0.8, 0.2, 0.4) |
:
Mmx] |
postfix .greyed (c: Color): Color == (c.r + c.g + c.b) / 3; |
Mmx] |
rgb (1, 0, 0).greyed |
:
Mmx] |
There is an output stream, which is called mmout. It can be used with the operator << to print strings:
Mmx] |
mmout |
:
Mmx] |
mmout << "Hello\n"; |
Hello
Mmx] |
i := 3; mmout<<"The square of "<<i<<" is "<<i*i<<"\n"; |
The square of is
The error stream, used to catch error message, is mmerr:
Mmx] |
mmerr <<"An error message"; |
Output streams can also be defined from files. Here we add a string the the file toto.txt:
Mmx] |
output_file_port ("toto.txt") << "Hi there\n"; |
and we load the contents of this file as a string:
Mmx] |
load ("toto.txt") |
:
Here are some usefull command to read and save contents in files. The
command to read a
Mmx] | include "example.mmx" |
The command to save a String in a file is save:
Mmx] |
save ("tmp.txt", "A string is stored in the file \n in two lines"); |
If now, you want to recover the content of a file, you can use the command load:
Mmx] |
load "tmp.txt" |
:
The files in a directory can be recovered by the command load_directory. The result is a vector of strings, which corresponds to the name of a file or a subdirectory:
Mmx] |
load_directory "." |
:
To check if a file or a directory exists, one can use the predicate readable?
Mmx] |
readable? "tmp.txt" |
:
The function use allows to load and use the types and functions exported in an external dynamic library:
Mmx] | use "numerix" |
If this example, the library libmmxnumerix.so should be in the loading path.
Mmx] |
Several functions are available to interact with the environment. To get the value of a variable defined in the environment, one can use get_env:
Mmx] | get_env "PWD" |
Mmx] | set_env ("DISPLAY", "arthur:0") |
To run a command in this environement, one can use the function system:
Mmx] |
system "ls" |
emacs_mode.en.tm
how_to.en.tm
index.en.tm
installation.en.tm
quick_start.en.tm
shell.en.tm
shell_tutorial.en.tm
syntax.en.tm
tmp.txt
toto.txt
:
Mmx] |
Comments starting with // extend to the end of the physical line. Such a comment may appear at the start of a line or following whitespace or code, but not within a string literal. Multi-line comments must be braced into /{ … }/ and can be nested.
|