CE QUI EST DÉCRIT CI-DESSOUS EST SUSCEPTIBLE DE CHANGER.
Dernière mise à jour du document : 28/09/2014
Tout n'est sûrement pas exhaustif. Ne pas hésiter à poser des questions. Cependant les grandes lignes du langage ne changeront pas.
Une variable qui n'a pas été initialisée, si elle est utilisée, renverra null
. Elle n'est pas différenciable des variables initialisée ayant la valeur null
.
Le séparateur d'instructions est le saut de ligne. Cependant, le ;
peut remplacer ce rôle, permettant ainsi de placer plusieurs instructions sur la même ligne.
Les variables ont une portée locale dans le bloc où elles sont définies. Si elle sont définies à la racine du programme, elle seront donc globales.
Les structures de contrôles sont des expressions. C'est-à-dire qu'elles retournent la dernière valeur de leur bloc et donc qu'il est possible de la récupérer dans une variable.
Les variables sont typées statiquement. Le typage est donc fixe et ne peut pas changer durant l'exécution excepté avec le type Var
qui permet de typer une variable dynamiquement.
_
est un caractère spécial qui indique le vide, il permet notamment d'indiquer à une valeur qu'elle ne doit pas être capturée.
Tout est objet. C'est à dire que ce code est correct :
Num a = 5 Str b = 120.to_str() # = "120"
Bool Num Char Str List<T> Dict<V> Var # Partie pas claire, à rectifier Func<(T n)*>:T Obj Void Null
null
est la valeur d'une variable non initialisée ou sans valeur.
Bool
prend pour valeur true (vrai) et false (faux).Num
correspond au type numérique.Char
correspond à un caractère.Str
correspond au chaînes de caractères.List<T>
correspond à une liste (un ensemble) de valeurs du type T.Dict<T>
correspond à un ensemble de clés (de type Str) auxquels sont associées une valeur de type T.Var
correspond au type dynamique, utile quand on ne sait pas quel type on veut recevoir dans une fonction.Func<(T n)*>:T
Obj
Void
Null
false
: false, 0, 0.0, "", [], {}, null
true
: le restePour évitez de multiples mots-clés pour définir des types, un seul mot-clé permet de créer des alias, des structures et des énumérations : type
# Alias type int = Num type ListOf<T> = List<T> type ListOfNum = ListOf<Num> type Add = (Num, Num -> Num) type EmptyFunc = (-> Void) # Structures type Person = { String name, Num age = 18 } # Enumérations type Dir = { Up, Down, Left, Right } type Color = { Red, Green, Blue, Rgb(Num, Num, Num) } type Volume = { No = 0 Low = 20 Medium = 50 High = 80 Max = 100 }
Les fonctions retournent par défaut la dernière expression. Le mot-clé return peut être utilisé seul pour ne rien retourner (la valeur null
sera renvoyée si le programme essaye de la récupérer) ou être utilisé avec une expression pour expliciter de manière précise la valeur retournée.
Num add(Num a, Num b) { a + b }
Les fonctions peuvent être surchargées. L'exemple précédent peut ainsi être surchargé ainsi afin de concaténer deux chaînes de caractères :
Str add(Str a, Str b) { a + b }
La fonction appelée dépend ainsi des types des paramètres qui y sont passés.
Les fonctions retournent la dernière expression excepté si un return
est rencontré.
Les arguments de fonctions peuvent avoir des valeurs par défaut.
Void ma_fonction(Num a, Num b = 5) { # ... }
L'appel d'une fonction demande obligatoirement des parenthèses, même si elle ne possède aucun paramètre.
Num mon_num = add(2, 5) # 7 Str mon_str = add("Hello", " World!") # "Hello World!"
Les fonctions peuvent accepter un nombre variable de paramètres.
Num somme(Num nb, Num args...) { # args sera un tableau (de nombres ici) contenant les valeurs passées lors de l'appel # ... }
Les fonctions à nombre de paramètres variables peuvent s'appeler de différentes manières.
Num nb nb = somme(2) # args vaudra [] (un tableau vide) nb = somme(2, 3, 4, 5) # args vaudra [ 3, 4, 5 ] # il est aussi possible de faire passer plusieurs valeurs via une liste # le ...[] sert à préciser qu'on fait passer plusieurs valeurs et non une liste nb = sommes(2, ...[ 3, 4, 5 ]) # args vaudra [ 3, 4, 5 ]
Il est possible de créer des fonctions anonymes. Elles servent généralement à faire des callbacks ou des fonctions qui changent durant l'exécution du programme.
# Fonction anonyme dans une variable # La fonction dans une variable peut être changée durant l'exécution mais pas surchargée Func ma_func = (Num a, Num b) { a + b } # Fonction anonyme dans une fonction une_fonction_avec_callback((Num a, Num b) { # ... }) # Fonction anonyme auto-appelée (Num a, Num b) { # ... }(3, 6)
Il est possible de retourner plusieurs valeur à la fin d'une fonction. En fait il s'agit de retourner une liste et de la récupérer via la syntaxe spécifique [ var1, var2, etc. ] = fonction().
une_fonction(Num a) { [ a + 1, a + 2, a + 3] } [ a, b, c ] = une_fonction(0) # a = 1 ; b = 2 ; c = 3 d = une_fonction(0) # d = [ 1, 2, 3 ] [ e, f, g ] = d # comme a, b et c [ b, a, c ] = [ a, b, c ] # b = 1 ; a = 2 ; c = 3
Il est possible de "binder" une fonction. _
permet d'indiquer des paramètres manquants qui seront les paramètres de la nouvelle fonction :
Num add(Num a, Num b) { a + b } # (Num, Num -> Num) Num add5 = add.bind(_, 5) # (Num -> Num) Num ma_var = add5(20) # = 25
La condition if
se compose ainsi : if ... { } else if ... { } else { }
.
if condition { # ... } else if condition { # ... } else { # ... }
Le if
fonctionne comme une expression et peut être assignée à une variable, c'est la dernière expression qui est retournée à la variable. Si aucune des conditions ne correspond, la variable prend la valeur du else s'il y en a un ou garde sa valeur s'il n'y en a pas.
Num a = if condition { 5 } else if condition { 0 } else { 1 }
Le if
profite de l'écriture raccourcie suivante :
Str a = if condition ? "ok" : "nop"
<, <=, >, >=, ==, <>, and, or, not, in
Exemple de l'opérateur in
qui retourne le nombre d'occurences :
List<Str> names = [ "Aymeric", "Guillaume", "Yannick" ] Bool has_yannick = "Yannick" in names # 1 Bool o_in_helloworld = "o" in "Hello World!" # 2 Dict<Num> scores = { "Aymerick" = 200, "Guillaume" = 180, "Yannick" = 20 } Bool has_guillaume = "Guillaume" in scores # 1
Le match
permet de tester plusieurs valeurs d'une variable ou expression.
match ma_var { "a" { # ... } "b" { # ... } else { # code par défaut, "else" peut être remplacé par "_" # ... } }
Le match
permet de tester des plages de valeurs, des valeurs multiples et des conditions :
match ma_var { 0 .. 5 { # [0;5] # ... } 6 ... 10, 50 ... 120 { # [6;10[ ou [50;120[ # ... } v if v > 200 { # si ma_var est supérieur à 200 # ... } }
Le match
fonctionne comme une expression et peut être assignée à une variable. Si aucune des valeurs n'est possédée par l'expression passée, la variable gardera sa valeur :
Str card = "as" Num card_value = match card { "valet" { 11 } "dame" { 12 } "roi" { 13 } "as" { 14 } else { card.to_num() } } # = 14
La boucle simple est une boucle infinie. Pour la stopper, il faut effectuer un break
.
loop { # ... }
Il est cependant possible de définir le nombre d'itérations ;
loop 5 { # 1 # 2 }
Il est aussi possible de définir un pas :
loop 8 by 2 { # 0 # 2 # ... }
La boucle while
itère dans la condition est respectée.
Num i = 5 while i-- { # i = 4 # i = 3 # ... }
La boucle do-while
fonctionne de la même manière que la boucle while
sauf qu'il y a une itération au minumum et que l'expression est évaluée à la fin de l'itération.
Num i = 5 do { # i = 5 # i = 4 # ... } while i--
La boucle itérative demande une valeur initiale et une valeur finale.
for i = 0 to 5 { # i = 0 # i = 1 # ... }
Vous pouvez aussi spécifier un pas :
for i = 0 to 12 by 2 { # i = 0 # i = 2 # ... }
Parcours tous les éléments de la liste.
List<Num> ma_list = [ 2, 3, 5, 7, 11, 13 ] for k, v in ma_list { # k = 0, v = 2 # k = 1, v = 3 # ... }
Parcours tous les éléments du dictionnaire.
Dict<Str> mon_dict = { "a" = "b", "b" = "c", "c" = "d" } for k, v in mon_dict { # k = "a", v = "b" # k = "b", v = "c" # ... }
Parcours chaque caractères d'une chaîne.
Str mon_str = "Hello" for k, v in mon_str { # k = 0, v = "H" # k = 1, v = "e" # ... }
Lors des boucles for
, il arrive que parfois vous ne souhaitiez pas nommer de variable itérative. Cela est possible grâce au mot-clé _
qui indique de ne pas capturer la valeur dans une variable :
for _ = 0 to 20 { }
Ainsi, la boucle aura 20 itérations mais aucune variable.
Cela fonctionne aussi pour les boucles for ... in
. Vous pouvez capturer, au choix, rien, la valeur, la clé ou les deux. Voici les différentes syntaxes utilisables :
# for in my_val { } # syntaxe à réfléchir # for _ in my_val { } # syntaxe à réfléchir # for _, _ in my_val { } # syntaxe à réfléchir # for v in my_val { } # syntaxe à réfléchir for _, v in my_val { } for k, _ in my_val { } for k, v in my_val { }
La création de classe fonctionne simplement. Comme la plupart des langages mais de manière simplifiée, sans visibilité ni futilités.
Le @
(this.
dans les autres langages) est obligatoire pour accéder à un attribut ou appeler une méthode de la classe.
class Point { public new(Num x, Num y) { @x = x @y = y } public Void add(Num x, Num y) { @x += x @y += y } public Void add(Point2D p) { @add(p.x, p.y) } } class Point3D < Point { public new(Num x, Num y, Num z) { @parent(x, y) @z = z } public Void add(Num x, Num y, Num z) { @add(p.x, p.y) @z += z } public Void add(Point3D p) { @add(p.x, p.y, p.z) } }
Il est possible d'ajouter des méthodes à une classe native (Str, Int, etc.) ou à une classe que vous avez créé ou que vous utilisez.
@
dans une classe native représente la valeur de l'objet (vous n'avez pas accès aux valeurs internes). @
dans une classe que vous avez créé ou que vous utilisez représente l'objet et avez donc accès aux attributs.
# Prototyper une classe native Num::negative_abs() { -@abs() # "@" représente ici la valeur du nombre } # Prototyper votre propre classe # Les sous-classes hérite des méthodes que vous créez ici Point::sub(Point p) { @x -= p.x @y -= p.y }
class Math { public const PI = 3.14159265359 public static get_pi() { return @PI } } Num PI pi = Math.PI pi = Math.get_pi()
Il y a deux méthodes pour accéder à une valeur dans une liste :
List<Num> ma_list = [ 0, 1, 2, 3, 4, 5 ] # Récupérer la valeur de l'indice 0 # ma_list.0 # syntaxe à réfléchir ma_list[0] ma_list.get(0)
Il y a trois méthodes pour accéder à une valeur dans un dictionnaire :
Dict<Num> ma_list = { "foo" = "bar", "bar" = "foo" } # Récupérer la valeur de la clé "foo" mon_dict.foo mon_dict["foo"] mon_dict.get("foo")
Aucune réflexion.
List<Num> a = [ 0 loop 5 ] # a = [ 0, 0, 0, 0, 0 ] List<Num> b = [ i for i from 0 to 4 ] # b = [ 0, 1, 2, 3, 4 ] List<Num> c = [ i for i from 0 to 4 if i % 2 == 0 ] # c = [ 0, 2, 4 ] Dict<Num> ages = { "Robert" = 34, "Léa" = 26, "Jean" = 55 } List<Str> names = [ name for name, _ in ages ] # names = [ "Robert", "Léa", "Jean" ]
pack fc.examples.plus_ou_moins use stdio as io use math Num nb = math.rand(1, 100) Num cpt = 0 Num val_test do { val_test = io.ask("Saisissez un nombre entre 1 et 100 : ").to_num() cpt++ if val_test > nb { io.writeln("C'est moins") } else if val_test < nb { io.writeln("C'est plus") } } while val_test <> nb io.writeln("Bravo, tu as gagné en ${cpt} coups !")
Num me = 38 Dict<Num> friends = { "Robert" = 32, "Paul" = 54, "Jean" = 29, "Jacques" = 42 } List<Num> ages = [ age for _, age in friends ] # [ 32, 54, 29, 42 ] ages.sort((Num a, Num b) { a - b }) # [ 29, 32, 42, 54 ]
# Syntaxe de Bootmonkey (BM) # Par Pif, booti386, Gorgio et SuperMonkey # Dernière mise à jour : 31/07/2014 enum Volume { LOW = 20 MEDIUM = 50 HIGH = 100 } interface Animal { Void } # S'inspirer de : # - http://haxe.org/manual/lf-pattern-matching.html # - http://fr.wikibooks.org/wiki/OCaml/Structures#Filtrage_par_motifs switch value { when < 0 { } when < 5 { } when >= 5 { } } when ::= < 0 (inférieur) | <> 20 (différent) | 0 or 5 (ou) | 0 to 5 (entre (bornes includes)) # Déclarer un type "type" nom_type = type exemple : type Player = { Str name, { Num x, Num y } position } # Déclarer une variable type nom_variable = valeur # Déclarer une constante "const" [type] nom_variable [ = valeur ] # Déclarer une fonction type nom_fonction(arguments) { } # Déclarer une classe [final] class NomClasse [ < NomClasseParente ] { } # Déclarer un attribut [public|protected|private] [static|const] type nom_attribut [ = valeur ] # Déclarer une méthode [public|protected|private] [static] [final] type nom_methode(arguments) { } # Suite de fibonacci Num fibo(Num n) { if n <= 1 { n } else { fibo(n - 1) + fibo(n - 2) } }
class Player { String name List<Card> cards new (String name) { this.name = name cards = [] } Void add_card(Card c) { cards.push(c) } } class Card { Int value String type String name new(Int value, String type) { this.value = value this.type = type name = "$value de $type" } Num get_value() { match value { "valet" { 11 } "dame" { 12 } "roi" { 13 } "as" { 14 } else { value.to_num() } } } } class Game { List<Card> cards List<Player> players new() { List<Var> value_cards = [ 2, 3, 4, 5, 6, 7, 8, 9, 10, "valet", "dame", "roi", "as" ] List<String> types_cards = [ "coeur", "pique", "trèfle", "carreau" ] for _, value in value_cards { for _, type in type_cards { add_card(value, type) } } players = [] } Void add_card(Var value, String type) { cards.push(new Card(value, type)) } Void add_player(String player_name) { players.push(new Player(player_name)) } } Game game = new Game() game.add_player("Yannick") game.add_player("Guillaume")
use
pour importer un packageVoici les portés des variables, fonctions, classes, interfaces et énumérations dans les packages :
private
par défautpublic
par défautprivate
= limité au fichierprotected
= limité au packagepublic
= ouvertnoref
pour copier la valeurref
L'entrée du programme s'effectue dans une fonction nommée main
que vous pouvez placer où vous voulez :
Num main(List<Str> args) { # votre code return 0 }
@nom_meta(cle=value)