en_anubis_doc.txt 36.4 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051

   
                                     The Anubis Project.
   
                          Short Documentation on the Anubis Language. 
   
                             Copyright (c) Alain Prouté 2001...2005. 
                                     All rights reserved. 
                                     

   
   Author: Alain Prouté
   
   Last revision of this file: June 2005.

   
   
   -------------------------------- Table of Contents ------------------------------------
   
   *** (1) Introduction. 
   
   *** (2). The language. 
      *** (2.1) Symbols. 
      *** (2.2) Operators. 
      *** (2.3) Syntax for lists. 
      *** (2.4) Paragraphs. 
         *** (2.4.1) 'read'. 
         *** (2.4.2) 'type'.
         *** (2.4.3) 'define'. 
         *** (2.4.4) 'public'. 
         *** (2.4.5) 'global'. 
      *** (2.5) Types. 
         *** (2.5.1) Primitive types. 
         *** (2.5.2) Address types. 
         *** (2.5.3) Functional types. 
         *** (2.5.4) Defined types. 
      *** (2.6) Definitions. 
      *** (2.5) Terms. 
         *** (2.7.1) Applicative terms. 
         *** (2.7.2) Conditionals. 
         *** (2.7.3) Abbreviated conditionals. 
            *** (2.7.3.1) 'if ... then ... else ...'.
            *** (2.7.3.2) '...; ...'.
            *** (2.7.3.3) Only one case. 
         *** (2.7.4) Selective conditionals. 
         *** (2.7.5) Explicit typing. 
         *** (2.7.6) Computing in advance ('with'). 
         *** (2.7.7) Functions. 
         *** (2.7.8) 'alert'. 
         *** (2.7.9) Starting a virtual machine ('delegate'). 
         *** (2.7.10) Waiting ('wait for').
         *** (2.7.11) Code protection ('protect').
         *** (2.7.12) File locking ('lock').
         *** (2.7.13) Other constructs. 
   
   *** (3) Remarks. 
      *** (3.1) Tools. 
      *** (3.2) Polysemie. 
      *** (3.3) Schemes. 
      *** (3.4) Equality between types. 
      *** (3.5) Strong preemption rule. 
      *** (3.6) Loops and terminal recursion. 
      *** (3.7) Conclusion. 
   
   ---------------------------------------------------------------------------------------

   
   
   
   
   *** (1) Introduction. 
   
   The  actual  documentation being  not  yet  written, I  try  to  describe the  language
   below. Of  course, this description is  too short to  be complete. The source  files in
   'anubis/library' are another  source of documentation, since they  are working examples
   (except for those which are still under construction).  The file:
   
                               anubis/library/predefined.anubis  
   
   is particularly important, because it  defines or declares fundamental concepts, and is
   perfectly reliable, since it is precompiled in the compiler, except that several things
   which are still under construction may have no corresponding instruction in the virtual
   machine. In that case, the virtual machine  will stop with a message.  Notice that this
   program has been developped under LINUX,  and that the Windows version still needs some
   work. 
   
   Also remember  that the messages of  the compiler are  rather detailed, and are  a good
   source of information.

   In  the explanations  below,  everything which  has  to be  written  textually is  also
   presented textually. On  the contrary, all concepts which are to  be replaced by actual
   expressions are enclosed by '<' and '>'. 

   In order to  have a first approach to  the Anubis language, you have  to understand the
   following concepts (they are explained below):
   
     - symbols (how they are written)
     - paragraphs
     - type  definitions  (including   'alternatives',  'components',  'constructors'  and
         'implicit destructors'),
     - definitions
     - terms  (including  'conditionals',  'applicative  terms' and  several  things  like
        'with', 'delegate', ...)
   
   
   Next you can try the example 'anubis/library/examples/hello.anubis'. 
   
   After you understand  the language, and depending on  what you plan to do,  you have to
   understand   some  system   tools.   The   most  important   ones  are   in   the  file
   'anubis/library/predefined.anubis'. Others are for example in 'anubis/library/web/', if
   you want to do something for the  Web. Actually, quickly exploring the whole library is
   not so much work.
   
   

   
   *** (2). The language. 
   
   
      *** (2.1) Symbols. 
   
   All symbols are made  of letters ('a' to 'z' and 'A' to 'Z'),  digits ('0' to '9'), and
   the underscore  '_'.  However, a symbol  cannot begin by a  digit. Furthermore, symbols
   which begin by an uppercase letter are reserved for type names (and type scheme names),
   while  other symbols must  be used  for all  other purposes.   In the  Anubis language,
   symbols (but not type names) may be overloaded (they may have several meanings; this is
   called  'polysemie', preferably to  the misleading  'polymorphism'), provided  that the
   compiler succeeds in resolving all ambiguities. This is performed by type unification.

   
   
      *** (2.2) Operators. 
   
   There are also a  small number of operators, which are either  unary or binary. A unary
   operator accepts one operand, while a binary operator accepts two operands. Examples of
   unary operators are:
   
      -    ('minus' sign)
      *    ('star' sign)
   
   These operators must be placed in front  of their unique operand. For this reason, they
   are  called 'unary prefix'  operators. Hence,  if 'a'  is the  operand, they  allow the
   writting of the following terms:
   
      -a
      *a
   
   
   Examples of binary operators are:
   
      +   ('plus' sign)
      *   ('star' sign)
      ^   ('caret' sign)
      |   ('vertical bar')
      &   ('ampersand')
      <<  ('left shift')
      >>  ('right shift')
      -   ('minus' sign)
      /   ('slash' sign)
      <   ('less' sign)
      =<  ('less or equal' sign)
      >   ('greater' sign)
      >=  ('greater or equal' sign)
      /=  ('non equal' sign)
      
   All the above  are 'binary infix' operators. They are called  'infix' because they must
   be placed between  their two operands. Hence, for  example, if 'a' and 'b'  are the two
   operands, you may write:
   
       a + b
   
   There is also a 'binary exfix' operator. If  'a' and 'b' are the two operands, the term
   constructed with this operator is written:
   
      [a . b]

   
   Of course, this syntax would be ambiguous without precedence and association rules. For
   example, if you write:
   
                                      a + b * c
   
   the compiler will read 'a + (b * c)', not '(a + b) * c', because the operator '*' has a
   higher 'precedence' than  the operator '+'. Furthermore, for  a given precedence level,
   the operators 'associate' either  to the left or to the right.  For example, the binary
   operator '-' ('minus' sign) is alone in its precedence level, and if you write:
   
                                      a - b - c
   
   the compiler  will read '(a - b)  - c', not 'a  - (b - c)'  (fortunately), because this
   precedence level associates to the left.
   
   The table  below show the  precedences and association  rules.  Each line in  the table
   represents a precedence level. The  precedence levels are presented in increasing order
   (the first line  has the lowest precedence  level). At the beginning of  each line, the
   association mode ('left'  or 'right') is indicated.  Notice that  we also have keywords
   in this table, not only operators.
   
   
   association
   mode               operators
   ---------------------------------------------------------------------------------------
   right              protect lock
   right              ,
   right              |-> |-name->
   right              :
   right              is with
   right              then else
   right              ;
   right              |
   right              &
   right              <<  >>
   right              <   >   =<   >=   =   <-   /= 
   right              +
   left               - (binary)
   right              * (unary and binary)
   left               /
   right              ^
   right              - (unary)
   right              ->
  
   
  
   
      *** (2.3) Syntax for lists. 
   
   The compiler also reads
   
       [a,b,c]
   
   as:
   
       [a . [b . [c . []]]]
   
   (this  is  reminiscent  from  Lisp).  This  allows to  write  lists  without  too  many
   symbols. See 'predefined.anubis' for the definition of lists.
   
   
   
   
   
      *** (2.4) Paragraphs. 
   
   An Anubis  source file is a  (possibly empty) sequence of  paragraphs. Comments between
   paragraphs may be written  freely (see 'library/examples/hello.anubis' for an example).
   Other  comments (within  paragraphs) may  be written  between /*  and */  (they  can be
   nested) or  between // and the  end of line.  The  compiler detects the  beginning of a
   paragraph when it encounters one of the following key words or key locutions:
   
read   
type 
public type
define
public define
global define
 
   provided that they are written in the leftmost column. As a consequence, to anihilate a
   paragraph  without erasing it,  you just  have to  put a  white space  in front  of the
   leading keyword.

   
         *** (2.4.1) 'read'. 
   
   'read' just tells the compiler to read  and compile the file whose name follows 'read'.
   The compiler always remembers  the names of the files already read  in, and there is no
   risk that it reads the same file two times (during the same compilation).
   
   This is more  or less equivalent to #include  in the C language. However,  you may also
   use the option -c when using the compiler. In this case, only the declarations of files
   'read' are actually  read. Only the main file  is compiled. This is useful  only if you
   develop  a big  program, with  long compile  times. If  the -c  option is  present, the
   compile produces no module. It just performs verifications. 
   
   
   
   
         *** (2.4.2) 'type'.
   
   'type' begins  a type definition.  They are explained  below, and many examples  may be
   found in the source files.
   
   
   
         *** (2.4.3) 'define'. 
   
   'define' begins a definition of a datum (or of a function, a special kind of datum). 
   
   
   
   
         *** (2.4.4) 'public'. 
   
   'public' says that the scope of the  definition is not limited to the current file. The
   definition (or type) may be referenced from within other files (using 'read').
   
   
   
   
   
         *** (2.4.5) 'global'. 
   
   'global  define' is  the  same as  'define', except  that  it produces  a module,  say:
   'my_module.adm'   (which   will   be   put   by   the   compiler   in   the   directory
   'my_anubis/modules/'), where 'my_module' is the  name of the function defined.  In that
   case the operands to the function must be declared as follows:

global define One
  my_module
    (
      List(String)  args  // mandatory unique argument representing the 
                          // arguments on the command line 
    ) =
  ...
   
   Here we  have chosen 'One'  as the return  type (but any  other type is  accepted). See
   'library/examples/hello.anubis' for an actual example. 
   
   
   
   
      *** (2.5) Types. 
   
   Types are of  the following sorts (some primitive types will  disappear from version 2,
   and will be replaced by defined types). Note: in 'predefined.anubis' you will find some
   other concepts, but they are in general still under construction.
   
   
   
   
         *** (2.5.1) Primitive types. 
   
      - String         character strings
      - ByteArray      arrays of bytes (Bytes are of type 'Int8'; see 'predefined.anubis')
      - Int32          32 bits signed integers
      - Float          64 bits floating point numbers
   
   
   
         *** (2.5.2) Address types. 
   
      - RAddr(T)       locations where data of type T may be read from
      - WAddr(T)       locations where data of type T may be written into
      - RWAddr(T)      locations where data of type T may be read from and written into
      
   (for the time being these types work only  for T = Int8). Data whose type is an address
   type are (up to now) files and network connections. 
   
   

   
         *** (2.5.3) Functional types. 
   
   Functional types are written like this:
   
      (<U_1>,...,<U_n>) -> <T>
   
   where <U_1>,...,<U_n> and <T> are types. Data  of the type above are functions taking n
   arguments of respective types <U_1>,...,<U_n>, and returning a result of type <T>. 
   
   It is also allowed to put an argument  name after the type of an argument. This name is
   ignored by the compiler, but using such names may enhance readability. For example, you
   may write your functional type as:
   
     (String text, Int32 x, Int32 width, Int32) -> One
   
   instead of:
   
     (String,Int32,Int32,Int32) -> One
   
   
   
   
   
         *** (2.5.4) Defined types. 
   
   Types may be  defined through a 'type  definition'.  Many examples may be  found in the
   source files. Nevertheless, here is the syntax, and what it means:
   
type <TypeName>:
  <alternative_1>,
  ...
  <alternative_n>.
   
   Here '<TypeName>' is the  name of the type.  It is a symbol  beginning by an upper case
   letter. Each  alternative describes data of the  defined type. Notice that  the type is
   intuitively (and  mathematically) the disjoint union  of the sets of  data described by
   its alternatives.
   
   Each alternative  is either a  single symbol (in  that case the  alternative represents
   only  one datum:  it  is a  'singleton'),  or a  symbol followed  by  a declaration  of
   'components' of various types, like this:
   
              <alternative_name>(<Type_1> <name_1>, ... , <Type_k> <name_k>)
   
   '<alternative_name>'  is a symbol  beginning either  by a  lower case  letter or  by an
   underscore.   <Type_1>,...<Type_k>  are  the  types  of the  components  of  the  datum
   described, <name_1>,...,<name_k> are the names  of these components.  The names are not
   mandatory  (components may  be anonymous).  The  number of  alternatives in  a type  is
   limited to 256.
   
   The meaning of the components is that  a datum belonging to this alternative is a tuple
   made of k data of respective types <Type_1>,...,<Type_k>.
   
   Hence, each  defined type is just  a disjoint union  of cartesian products of  types (a
   so-called 'polynomial type'). See  the self-explanatory examples in 'predefined.anubis'
   and    other     source    files    like     'anubis/library/tools/basis.anubis'    and
   'anubis/library/web/html.anubis'.
   
   Each alternative  name gives rise to  a function called a  'constructor'. This function
   has as  many arguments  as the  number of components  in the  alternative, in  the same
   order, and with the same types. The target type of a constructor is the type defined by
   the type definition. 
   
   If, in a  type definition, all alternatives  have a component of some  common type 'T',
   with  some common  name  'n', then  the  compiler produces  automatically an  'implicit
   destructor' which is a  function named 'n', whose source type is  the defined type, and
   whose target type is 'T'.
   
   For example, if you define a type like this: 
   
type T:
  a(U x),
  b(U x, V y). 
   
   Intuitively, when interpreted as  a 'set', this type is just the  disjoint union of 'U'
   and of the cartesian product 'UxV'. 

   For this type, the compiler produces three functions: 
   
   'a'       of type (U) -> T           (first constructor)
   'b'       of type (U,V) -> T         (second constructor)
   'x'       of type T -> U             (implicit destructor)
   
   Actually, the implicit destructor is simply  defined by the compiler as follows (recall
   that '_' is a regular symbol):
   
define U
  x
    (
      T _
    ) = 
  if _ is 
    {
      a(x) then x, 
      b(x,y) then x
    }. 
  
   But of course, the compiler produces  no implicit destructor named 'y', because not all
   data in 'T' have a component named 'y'.
   

   The  compiler  also  accepts  exceptional  syntaxes  for  alternatives.  They  are  the
   following:
      
      [ ]                                        this is treated like a symbol (no component)
      [<Type_1> <name_1> . <Type_2> <name_2>]    (2 components)
   
   See  the  definition   of  the  type  scheme  'List'   in  'predefined.anubis'  for  an
   example. Those are also accepted (but seldom used):
   
      <Type_1> <name_1> + <Type_2> <name_2>
      <Type_1> <name_1> * <Type_2> <name_2>
      <Type_1> <name_1> ^ <Type_2> <name_2>
      <Type_1> <name_1> | <Type_2> <name_2>
      <Type_1> <name_1> & <Type_2> <name_2>
      <Type_1> <name_1> -> <Type_2> <name_2>
      <Type_1> <name_1> = <Type_2> <name_2>
      <Type_1> <name_1> => <Type_2> <name_2>
      <Type_1> <name_1> << <Type_2> <name_2>
      <Type_1> <name_1> >> <Type_2> <name_2>
      <Type_1> <name_1> - <Type_2> <name_2>
      <Type_1> <name_1> / <Type_2> <name_2>
      <Type_1> <name_1> (mod <Type_2> <name_2>)
      <Type_1> <name_1> < <Type_2> <name_2>
      <Type_1> <name_1> /= <Type_2> <name_2>
      <Type_1> <name_1> =< <Type_2> <name_2>
      ~ <Type_1> <name_1>
   
   
   
   
   
      *** (2.6) Definitions. 
   
   We already have an example above (the  implicit destructor 'x'). The syntax is the same
   one for the keywords (or key locutions):
   
define 
public define
global define
 
   Hence, we give  it only for 'define'.  A 'top level' definition of  function looks like
   this:
   
define <Return Type>
  <name of function>
    (
      <Type_1> <operand_1>,
      ...
      <Type_n> <operand_n>
    ) =
  <body_of_definition>. 
   
   The  '<body_of_definition>' is  a so-called  'term'. Notice  the commas  separating the
   declarations of the operands, the '=' sign  before the body (which maybe was not a very
   good design  idea), and the  dot after  the body of  the definition. Operand  names are
   mandatory.
   
   If there is no operand at all, the definition is written like this:
   
define <Type>   
  <name of datum>
    =
  <body_of_definition>. 
   
   and the datum defined is of type <Type>. 


   The compiler also  accepts several exceptional syntaxes for  definitions.  For example,
   the  binary operator  '+' may  receive several  definitions (actually,  it  already has
   several definitions  in 'predefined.anubis'). The syntax  for such a  definition is the
   following:
   
define <Type>
   <Type_1> <operand_1> + <Type_2> <operand_2>
     =
  <body_of_definition>. 

   The same rule applies to the following binary infix operators:
   
       *   ^   |   &   <<   >>   -   /   <   =<   /=
   
   Notice that '>' and '>=' cannot be defined. When you define '<', the compiler considers
   that you have defined '<' and '>' at the same time. Later, when he finds
   
                a > b
   
   he simply reads: b < a. 
   
   Similarly, the unary prefix operator '-' ('minus' sign) may be (re)defined as follows:
   
define <Type>
   - <Type_1> <operand_1> 
     =
  <body_of_definition>. 
   

   See   'anubis/library/basis.anubis'  for   several  examples   of   such  syntactically
   exceptional definition.
   
   
   
   
   
   
      *** (2.5) Terms. 
   
   

         *** (2.7.1) Applicative terms. 
   
   They are just functions applied to arguments:
   
        <f>(<a_1>,...,<a_n>)
   
   Nevertheless if '<f>' may be interpreted as  a function with no operand '<f>' itself is
   an applicative  term. (This  was in  fact a bad  idea to  identify functions  with zero
   operands with  the result of  applying this function  to zero operands.   This 'unlucky
   feature' will disappear from version 2).
   
   
   
   
   
         *** (2.7.2) Conditionals. 
   
   They allow  to work  with data of  defined types  according to their  alternatives. The
   syntax is:
   
if <test> is 
  {
    <case_head_1>   then   <case_body_1>, 
    ...
    <case_head_n>   then   <case_body_n>
  }
   
   The type of  '<test>' must be a defined  type. There must be exactly one  case for each
   alternative of this  type, and in the same  order. The precise syntax of  cases will be
   understood easily from  the examples in the  source files. Notice that the  type of the
   conditional itself is the  type which is common to all case  bodies.  The symbols which
   appear within  parentheses in the  case heads are  call 'resurgent symbols',  and their
   scope is just the corresponding case body. 

   There are of course exceptional syntaxes  for cases of conditionals which correspond to
   exceptional syntaxes for alternatives.  For  example, a function 'length' computing the
   length of a list may be defined (recursively) as follows:
   
define Int32
   length
     (
       List($T) l
     ) =
   if l is 
     {
       [ ]           then 0, 
       [head . tail] then 1 + length(tail)
     }. 

   This example shows  why Anubis avoid systematically certain  errors that other compiler
   cannot detect. It is  clear that you cannot consider the head of  the tail of the empty
   list, since they are simply  syntactically not accessible.  Actually, components may be
   accessed only when it is certain that they exist.
 
   
   
   
         *** (2.7.3) Abbreviated conditionals. 
   
   There are some special cases (abbreviations):
   
   
            *** (2.7.3.1) 'if ... then ... else ...'.
   
   'if <test> then <a> else <b>' means:
   
         if <test> is 
           {
             false then <b>, 
             true then <a>
           }
   
   Of    course,   in   that    case   '<test>'    must   be    of   type    'Bool'   (see
   'anubis/library/predefined.anubis').
   
   
            *** (2.7.3.2) '...; ...'.
   
   '<a>; <b>' means:
   
         if <a> is 
           { 
             unique then <b> 
           }
   
   In this case, '<a>' must be of type 'One'. 
   
   
   
   
            *** (2.7.3.3) Only one case. 
   
   If the type of the test has only one alternative, the conditional
   
      if <test> is
        {
          <case_head>   then   <case_body>
        }
   
   may be abbreviated to:
   
      'if <test> is <case_head> then <case_body>'
   
   Another  syntax is  allowed,  which  may seem  more  natural, when  there  is only  one
   alternative:
   
      'since <test> is <case_head>, <case_body>'
      
   'since' is a keyword like 'if', hence forbidden as a symbol. 
   
   
   
   
   
         *** (2.7.4) Selective conditionals. 
   
   In some  circumstances, in particular when  the type of  the test of a  conditional has
   many alternatives,  we may  want to  give a particular  treatement to  the data  of one
   'selected' alternative and the same 'default' treatement to data of other alternatives.
   In this case, use a 'selective conditional':
   
       if <test> is <selected_case_head> 
       then <selected_case_body>
       else <default_treatement>
   
   

   
   
   
         *** (2.7.5) Explicit typing. 
   
   If '<t>' is any term, which is supposed  to be of type '<T>', you may help the compiler
   to choose the right interpretation by explicitly typing the term, as follows:
   
                                          (<T>)<t>
   
   This  is  needed  in  some  circumstances,  and  in others  may  simply  speed  up  the
   compilation.

   There is no  'transtyping' in Anubis, in other  words, you cannot change the  type of a
   datum. The only thing you can do is helping the compiler (and the reader of your source
   file) to find the type of a term.
   
   
   
   
   
         *** (2.7.6) Computing in advance ('with'). 
   
   You may precompute something before using it. The term:
   
          with <x> = <a>, <t>
   
   where '<x>' is a symbol, '<a>' and '<t>'  two terms, is of the same type as '<t>'. This
   is just a local definition (no side effect, because you cannot assign '<x>' a new value
   from within '<t>', which is the scope of the local definition).
   
   You may also combine several local definitions:
   
          with <x> = <a>, 
               <y> = <b>, 
               <z> = <c>, 
            <t>
   
   In that case, '<b>' may use '<x>', and '<c>' may use '<x>' and '<y>'.  Of course, '<t>'
   may use '<x>', '<y>' and '<z>'.
   
   
   
   
         *** (2.7.7) Functions. 
   
   Anubis is  a fully functional language,  like CAML and  not too early versions  of Lisp
   (and also JavaScript !).  This means that functions can be constructed, not only at the
   'top level', i.e.  using a 'define' paragraph, but anywhere within a term, and that the
   function  constructed  will remember  the  precise context  within  which  it has  been
   constructed.
   
   The syntax for writting a function with k arguments is the following:
   
                               (<T_1> <x_1>, ...,<T_k> <x_k>) |-> <t>
   
   where <T_1>,...,<T_k> are the types of the arguments, where <x_1>,...,<x_k> are symbols
   (the names of  the arguments), and where '<t>'  is a term. The term  (<T_1> <x_1>, ...,
   <T_k> <x_k>)  |-> <t> is  called a 'lambda-expression',  despite the fact that  we have
   prefered the usual mathematical 'maps to' notation, i.e. the arrow:
   
                                            |->
   
   over the Lispian syntax using the keyword 'lambda'.
   
   The important fact is that functions defined that way remember the context within which
   they where defined.  For example you may write the term:
   
                           with y = (Int32)3, 
                             (Int32 x) |-> x+y
   
   which represents the function 'which adds 3'. If you use this function within a context
   where another 'y'  is defined, the function  will still add 3.  Hence  for example, the
   term:
   
      with y = (Int32)3,            // define 'y' as '3'
           f = (Int32 x) |-> x+y,   // define 'f' as the function which adds 'y' (i.e. 3)
           y = (Int32)7,            // now define another 'y'
       f(1)                         // and apply 'f' to '1'
   
   represents the  integer '4', not  the integer  '8', despite the  fact that 'y'  has the
   value 7 in the context where 'f' is used. Doing another way would be an error, known as
   a 'capture of variable'.
   
   
   You can also  construct recursive functions with  the arrow, but in order  to be called
   from  within its  own body,  the function  must have  a name.  Hence, instead  of using
   the simple (anonymous) arrow, use this one:
   
                                          |-name->
   
   which  is an arrow  with a  name (here  the name  is 'name'),  also called  a 'labelled
   arrow'. As an example, you may write:
   
        with f = (List(String) l) |-len->
                    if l is 
                      {
                        [ ] then 0,
                        [h . t] then 1+len(t)
                      },
          f(["a","b","c","d"])
   
   This term is of type Int32, and its value is 4. Notice that in the expression above the
   symbol 'len' is declared (representing the function), and its scope is just the body of
   the function.
   
   Now, what  if you want to  construct cross recursive  functions with the arrow  '|->' ?
   Assume that we want to construct two cross recursive functions 'f' and 'g', and that we
   begin by  'f'. The  problem is that  we cannot call  'g' from  within the body  of 'f',
   because 'g' is  not yet declared. However, there is a  beautiful (and functional) trick
   to solve this problem. It is not always  obvious to put it at work. I will just examine
   an example.
   
   Assume that the functions 'f' and 'g' could be defined at the top level as follows:

      type U:...  // forward declaration for cross recursive types

      type T: 
        a,
        b(T,U). 
   
      type U:
        c,
        d(T,U). 
   
      define T g(U u).  // forward declaration for cross recursive functions

      define T f(T t) = if t is 
                          {
                            a        then a, 
                            b(t1,u1) then b(f(t1),g(u1))
                          }.
   
      define T g(U u) = if u is 
                          {
                            c        then a, 
                            d(t1,u1) then b(f(t1),g(u1))
                          }.
   
   You  can see  that f  and g  are cross  recursive, and  that the  recursion  is correct
   (terminates). Define them with labelled arrows as follows:
   
      with phi = (T t, U -> T g) |-phi-> if t is 
                                           {
                                             a        then a, 
                                             b(t1,u1) then b(phi(t1,g),g(u1))
                                           },
             g = (U u)|-g-> if u is 
                              {
                                c        then a, 
                                d(t1,u1) then b(phi(t1,g),g(u1))
                              },
             f = (T t) |-> phi(t,g), 
        // at that point you have f and g at hand. 
   
   Full functionality has  many important applications.  It is used in  a essential way in
   dynamic variables  monitoring (see predefined.anubis),  in the graphical  interface, in
   the data base, etc...
   
   
   
   
   
   
         *** (2.7.8) 'alert'. 
   
   'alert' may replace  any term of any  type. If 'alert' is executed  the virtual machine
   stops with  a message  indicating the file  and line  number of this  'alert'. However,
   other virtual  machines continue to run.  'Alert' will disappear from  version 2, where
   higher order logic provides better mecanisms. 
   
   
   
   
   
   
         *** (2.7.9) Starting a virtual machine ('delegate'). 
   
   If '<t>' and '<u>' are two terms,
   
               delegate <t>, <u>
   
   is  a term  of the  same  type as  '<u>'. The  execution  of 'delegate  <t>,<u>' is  as
   follows. The virtual  machine starts another virtual machine to  which it delegates the
   execution  of '<t>'. The  original virtual  machine executes  '<u>'.  Hence,  '<t>' and
   '<u>' are executed  in parallel. Notice that 'anbexec' has  its own scheduler built-in,
   and manages multitasking itself without using threads.
   
   
   
   
   
   
   
         *** (2.7.10) Waiting ('wait for').
   
   The expression:
   
               checking every <n> milliseconds, wait for <t> then <u>
   
   where '<n>' is a term of type 'Int32', '<t>' is a term of type 'Bool', and '<u>' a term
   of any type 'T',  is a term of type 'T'.  When executed,  the virtual machine waits for
   condition '<t>'  to be satisfied  (i.e. 'true'), and  then executes '<u>'.   Of course,
   other virtual  machines are running during  that time.  The condition  '<t>' is checked
   every '<n>' milliseconds (as the syntax recalls clearly).  Notice that the machine also
   waits '<n>' milliseconds  before the first computation of  '<t>'.  Note: 'milliseconds'
   may also  be written 'millisecond'.   See the function 'sleep'  in 'tools/basis.anubis'
   for an example.
   
   
   
   
   
         *** (2.7.11) Code protection ('protect').
   
   If '<t>' is  a term, then 'protect  <t>' is a term of  the same type and  with the same
   semantics  as '<t>'.  The  sole difference  with '<t>'  alone is  that, if  prefixed by
   'protect' the term '<t>' cannot be executed simultaneously by several virtual machines.
   In other  words, when a machine  begins the execution of  '<t>', it locks  the piece of
   code corresponding  to '<t>'. If another machine  tries to execute '<t>',  it will find
   '<t>' locked.  In this case, the second machine gives up, waiting for the other machine
   to unlock 't'. Note that, even if a  machine locks a term during a long time, the other
   machines are  still working.  The only thing  is that they cannot  execute '<t>' during
   that time, and in that case must wait that '<t>' be unlocked.
   
   'protect' is typically  used to update data  in files, that is: read  the file, compute
   the new  data and save  them back.  Only  one machine should update  a file at  a time,
   otherwise, the result may be desastrous.
   
   A demo of 'protect' may be found in 'anubis/library/examples/try_protect.anubis'. 
   
   
   
   
   
         *** (2.7.12) File locking ('lock').
   
   This is similar to 'protect', but instead  of protecting a piece of code, it protects a
   file name. The syntax is:
   
               lock <filename>, <body>
   
   where '<filename>' is any term of type  'String' which computes the name of a file. The
   type of this  term is the type of  '<body>'. The term '<body>' following  the comma may
   read and  write this file assuming  that no other  virtual machine can do  it, provided
   that:
   
      (1) all other virtual machines also try  to lock the file before reading or writting
          it. If another  virtual machine writes into the file without  trying to lock it,
          it will be able to write even if the file is locked. This point may (and should)
          change in the future.
   
      (2) no other  anubis program (anbexec)  is running trying  to access the  same file,
          even through a lock.
   
   Indeed, the locking of the file is  purely internal to the anbexec running (it does not
   do  anything to  the  file  itself, even  not  verify that  the  file  exists; it  just
   associates the file name to the virtual  machine), and two anbexecs running at the same
   time cannot know which file has been locked by the other one.
   
   Of  course,  if  '<filename>' is  already  locked,  the  virtual machine  waits  before
   executing '<body>',  letting other virtual  machines do their  job.  Among them  is the
   machine which will unlock the file name.
   
   Note: 'protect'  and 'lock' are conveniently  superseded by the  functionalities of the
   'secured data base server' (see 'anubis/library/data_base/common.anubis').
   
   
   
   
   
         *** (2.7.13) Other constructs. 
   
   Of course,  there are  other constructs  in the language,  but you  have seen  the most
   important  here.   You  will  easily   guess  the  rest   from  the  source   files  in
   'anubis/library/', and in particular in 'predefined.anubis'.
   
   

   
   
   
   
   *** (3) Remarks. 
   
   To conclude this  very short documentation, we discuss several points  which may be not
   so obvious from our source files.

   
      *** (3.1) Tools. 
   
   Many  tools  are  available from  our  source  files.  Have  a  look at  the  files  in
   'anubis/library/' and in its subdirectories. In particular, you will find all the stuff
   for making a server or a client program in 'library/predefined.anubis'.

   
   
   
      *** (3.2) Polysemie. 
   
   (improperly called 'polymorphism' in other languages).  The Anubis language accepts the
   use of the same  name for several definitions, provided that either  the return type or
   the operand  types are different.  Of  course, private definitions (those  which do not
   begin by 'public')  cannot create any conflict with other  private definitions in other
   files.
   
   
   
   
      *** (3.3) Schemes. 
    
   You may also use type parameters (representing arbitrary types). They have the form $T,
   where T has the syntax  of a type name. See the examples in our  source files, and as a
   leading example the definition of 'List' in 'predefined.anubis'. 


   
   
      *** (3.4) Equality between types. 
   
   Two distinct  types cannot have  the same  name (except if  they are both  private (non
   public) in distinct  files).  Furthermore, the language Anubis  does not consider types
   (with  distinct names)  which are  defined the  same  way as  the same  type. They  are
   different types. This is a 'feature' which helps the compiler to grasp more of what you
   have in mind (intentional semantics).
   
   

   
      *** (3.5) Strong preemption rule. 
   
   This is the  very opposite to polysemie.  This  rule says that if a symbol  has a local
   definition, only this definition is to be considered within its scope. Hence, any local
   definition hides any previous local or global definition of the same symbol.
   
   
   
   
      *** (3.6) Loops and terminal recursion. 
   
   The  Anubis language  has no  'loop' construct,  but the  compiler  eliminates terminal
   recursion  automatically, so  that loops  may  be realized  that way.   Again, see  the
   examples, and explanations in 'anubis/library/predefined.anubis'.
   
   
  
   
   
      *** (3.7) Conclusion. 
   
   I hope  that you will  enjoy Anubis, whose  main quality is  to provide a  very secured
   programming paradigm. In  other words, when the compiler says  nothing (your source has
   been compiled successfully),  it is very unlikely that your text  be faulty (except for
   non ending  recursions).  This  is a great  constrast with  some 'a la  mode' languages
   (notably languages for the World Wide Web).
   
   Please, email any comment to the author:     alain.proute@free.fr