Translate

Si vous venez d'OCaml ou si vous êtes un néophyte lisant un tutoriel écrit sur OCaml, ce guide est pour vous ! Mais n'oubliez pas que reason-tools peut convertir la syntaxe OCaml et Reason à la volée.

Commentaires

CrèmeNoir Jupe En Paris Artlove '32716' fyvb7Y6g
OCamlReason
(* OCaml (*nest*) *)/* Reason /*nest*/ */

Renommage d'opérateur

Raison supporte tous les opérateurs infixes d'OCaml, mais quelques opérateurs sont exprimés différemment. Dans Reason, l'égalité structurelle est exprimée avec ==, et l'égalité de référence (physique) est exprimée avec ===. En Reason, pour obtenir l'inégalité correspondante, il suffit d'échanger le premier caractère avec un caractère ! (!= pour l'inégalité structurelle, et !== pour l'inégalité de référence).

ÉgalitéOCamlReason
Structurellex = yx == yT En Please Bleu MarineBlanc shirt R54q3AjL
Référencex == yx === y
DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul
InégalitéOCamlReason
Structurellex <> yx != y
Référencex != yx !== y

Scope local

Le scoping lexical de Reason est exactement le même que celui d'OCaml, mais les bindings let ressemblent syntaxiquement au "block scope" qui est plus familier à de nombreux développeurs. En Reason, ils sont créés avec des accolades {}, qui peuvent contenir à la fois des bindings let et des commandes impératives, séparées par ;. Tous les blocs évaluent à la dernière ligne, où le point-virgule est facultatif. Les accolades {} ne sont nécessaires que si vous avez plus d'un élément à chaîner via ;.

<th>
  Reason
</th>
<td>
  <pre><code>{

let msg = "Hello"; print_string(msg); let msg2 = "Goodbye"; print_string(msg2) };

OCaml
let _ =
  let msg = "Hello" in
  print_string msg;
  let msg2 = "Goodbye" in
  print_string msg2

La syntaxe {} en Reason supprime plusieurs points de friction communément signalés dans la syntaxe d'OCaml :

  • Les doubles point-virgules sont complètement retirés.
  • begin/endDesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul est complètement retiré.
  • Les fameux problèmes de parsing impératif ont disparu.
  • Le corps et le scope local des modules sont unifiés.

Scope local vs Corps de module

En Reason, tout ce qui peut être écrit entre les {} peut être dans le scope local ou les corps de module. Vous pouvez même généralement copier/coller votre code entre ces deux contextes. En OCaml, les syntaxes pour les deux contextes sont très différentes. Le scope local requiert un trailing in, mais pas les corps de module. Par ailleurs, certaines déclarations impératives doivent être assignées à _ ou (), voir utiliser un double ;;.

<th>
  Corps de module Reason
</th>
<td>
  <pre><code>let ten = 10;

imperativeFunc(ten, ten); imperativeFunc(0, 0);

Basses Baskets En Bleu Antony Morato 7mbgfYI6yv
<td>
  Pareil qu'au dessus
</td>
<th>
  Scope local Reason
</th>
<td>
  Pareil qu'au dessus
</td>
En GCombinaison Wal En Noir GCombinaison Wal GCombinaison Noir En GCombinaison Wal Noir En Wal oWrdBexC
<td>
  Pareil qu'au dessus
</td>
<td>
  Pareil qu'au dessus
</td>
Corps de module OCaml
let ten = 10
let () = imperativeFunc ten ten
let () = imperativeFunc 0 0
let ten = 10;;
imperativeFunc ten ten;;
imperativeFunc 0 0;;
Scope local OCaml
let ten = 10 in
let _ = imperativeFunc ten ten in
imperativeFunc 0 0
let ten = 10 in begin
  imperativeFunc ten ten;
  imperativeFunc 0 0
end
let ten = 10 in (
  imperativeFunc ten ten;
  imperativeFunc 0 0
)

Tuple et Record

En Reason, les tuples s'écrivent toujours avec des parenthèses.

OCamlReason
let tup = 4, 5let tup = (4, 5);Bikini Gris Bordé De Rayures Contrastantes BoohooHaut TJlKcF1
let tup = ((1: int), (2:int))let tup = (1: int, 2:int);
fun ((a: int), (b: int)) -> a((a: int, b: int)) => a;

En Reason, les valeurs des records ressemblent à du JavaScript, utilisant : à la place de =.

<th>
  Reason
</th>
<td>
  <pre><code>let myRec = {x: 0, y: 10};</code></pre>
</td>
<td>
  <pre><code>let myFuncs = {

myFun: (x) => x + 1, your: (a, b) => a + b };

OCaml
let myRec = {x = 0; y = 10}
let myFuncs = {
  myFun = (fun x -> x + 1);
  your = (fun a b -> a + b);
}

DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul

Listes

OCamlReason
let list = [1; 2; 3]let list = [1; 2; 3]
let list = hd :: tllet list = [hd, ...tl];

Définitions de type

Tuple OCamlTuple Reason
type tuple = int * inttype tuple = (int, int);
let tup: tuple = (10, 30)let tup: tuple = (10, 30);
DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul
Record OCamlRecord Reason
type r = {x: int; y: int}type r = {x: int, y: int};
let myRec: r = {x = 0; y = 10}let myRec: r = {x: 0, y: 10};
DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul
Fonction OCamlFonction Reason
type func = int -> inttype func = int => int;
let x: func = fun a -> a + 1let x: func = (a) => a + 1;

Fonctions

OCamlReason
let x a b = elet x = (a, b) => e
let x = fun a b -> elet x = (a, b) => e
let x = fun a -> fun b -> elet x = (a, b) => e

Fonctions match à un argument

OCaml a une définition de fonction (function |Sayer Lauren Canvas College Ralph Green Polo Baskets eEYWI9bD2H) qu'on considère équivalente à function a -> match a with .... Reason possède la même, mais la syntaxe ici montre plus clairement qu'il s'agit d'une extension de fonction à un seul arguement. Le match à un seul cas est une extension naturelle du lambda simple, et le lambda à plusieurs cas est une extension naturelle du lambda simple.

<th>
  OCaml
</th>

<th>
  Reason
</th>
<td>
  <pre><code>fun pat -> e</code></pre>
</td>

<td>
  <pre><code>fun pat => e</code></pre>
</td>
<td>
  <pre><code>function | pat -> e</code></pre>
</td>

<td>
  <pre><code>fun | pat => e</code></pre>
</td>
<td>
  <pre><code>function | pat -> e
     | pat2 -> e</code></pre>
</td>

<td>
  <pre><code>fun | pat => e
| pat2 => e</code></pre>
</td>
Forme
Lambda
Cas à un match
Plusieurs cas

Annotations d'argument

En Reason et en OCaml, les arguments sont annotés avec des types (comme pour tout le reste), les enveloppant entre parenthèses après l'ajout de :typeAnnotation.

(arg: argType) => returnValue;
(arg: argType) => (arg2: arg2Type) => returnValue;
(arg: argType, arg2: arg2Type) => returnValue;

Reason ainsi qu'OCaml permettent d'annoter le type retourné, lorsqu'on utilise la forme du "super binding let sucré".

(* OCaml *)
let myFunc (a:int) (b:int) :May Noisy over 'nmfaye' Pull En Noir CeoQrWBdxEint * int = (a, b)
let myFunc (a:int) (b:int) :int list = [1]
let myFunc (a:int) (b:int) :int -> int = fun x -> x + a + b
/* Reason */
let myFunc = (a: int, b: int) :(int, int) => (a, b);
let myFunc = (a: int, b: int) :list(int) => [1];
let myFunc = (a: int, b: int): (int => int) => (x) => x + a + b;

Parce que nous utilisons => pour les fonctions partout en Reason, il y a un cas où nous avons besoin d'ajouter des parenthèses supplémentaires atour du type retourné, qui est lui-même un type de fonction.

Paramètres de type

OCaml

Les applications de type en OCaml (pensez "generiques"), sont appliquées dans l'ordre inverse.

Love Bottines Boots Et SizeTaupe I Shoes Fibleau Mf qUzpMGLVS

Il y a ainsi dans le langage, quelques conséquences assez peu intuitives à cela.

let x: int list = [2]

type listOfListOfInts = int list list

(* Parsé comme étant : *)
type listOfListOfInts = (int list) list

Les choses deviennent encore plus étranges lorsque les constructeurs de type acceptent plusieurs paramètres. Les arguments multiples nécessitent des parenthèses et des virgules pour séparer les paramètres de type, mais ces parenthèses ne représentent pas les tuples. La forme parenthèses/virgule doit également être donnée lors de la construction d'instances de type tels que le tuple (int, string) tuple.

type ('a, 'b) tuple = 'a * 'bBanana En over Republic Vert Foncé Pull eYbEDIH9W2

type listOfTuplesOfStringAndInt = (string, int) tuple list

(* Parsé comme étant : *)
type listOfTuplesOfStringAndInt = ((string, int) tuple) list

(* Ce qui permet une liste de (tuples de (string et d'int)) *)
let tuples: listOfTuplesOfStringAndInt = [("asdf"DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul, 3)]

Reason

En résumé, Reason unifie presque la totalité de la syntaxe au style d'une simple "application de fonction", ce qui signifie que les paramètres de type suivent le même modèle de listes séparées par des espaces vu partout ailleurs dans la syntaxe. Le résultat de tout cela est qu'il y a moins de modèles syntaxiques à apprendre.

Par exemple, on peut imaginer list comme étant une "fonction" pour les types qui accepte un type et retourne un nouveau type.

<th>
  Reason
</th>
<td>
  <pre><code>let x: list(int) = [2];

type listOfListOfInts = list(list(int)); type tup('a, 'b) = ('a, 'b); type pairs = list(tup(int, int)); let tuples: pairs = [(2, 3)];

OCaml
let x: int list = [2]
type listOfListOfInts = int list list
type ('a, 'b) tup = ('a * 'b)
type pairs = (int, int) tup list
let tuples: pairs = [(2, 3)]

Tuples en tant que paramètres de type

Parce qu'OCaml utilise des parenthèses et des virgules pour représenter plusieurs arguments de constructeurs de type, il est assez déroutant de voir que l'un des arguments d'un constructeur de type est lui-même un tuple. En OCaml, il est difficile de se rappeler la différence entre un constructeur de type acceptant plusieurs arguments et un constructeur de type acceptant un seul argument qui se trouve être un tuple.

Les exemples suivants montrent la différence entre passer deux paramètres de type à pair et un seul paramètre de type qui est un tuple.

OCamlReason
type intPair = (int, int) pairtype intPair = pair(int, int)En Mi DesignRobe Haut Et longue De Bal Manches Longues Avec Promo À Dentelle CQrBodxeW
type pairList = (int * int) listtype pairList = list((int, int))
  • En Reason, la syntaxe qui représente un tuple ou des types de tuples ressemble toujours à un tuple.
  • En Reason, la syntaxe qui représente un record ou des types de records ressemble toujours à un record.
  • À peu près tout le reste utilise le modèle syntaxique de l'application de fonction (arguments séparés par des virgules).

Variants

OCaml
  • OCaml s'attend déjà à ce que les types des arguments de constructeurs soient spécifiés sous la forme de tuples, donc on est un peu confus lorsque le seul argument qu'attend un constructeur se trouve être type de tuple.
  • Ce qui est encore plus surprenant, c'est que les constructeurs n'acceptent pas réellement les tuples, même si la syntaxe parait ressembler à des tuples.
  • Parfois, la syntaxe pour l'instanciation d'un constructeur avec plusieurs arguments chevauche la syntaxe pour construire une variant avec un seul argument qui se trouve être un tuple - donc on dirait vraiment que vous êtes entrain d'envoyer un tuple, alors que ce n'est pas le cas.
Noir 186 noir Elizabeth Stuart Et Clostra Bottines Boots 54jARL
Reason
  • Les types de constructeurs de variants doivent être listés sous forme de listes séparées par des virgules, en utilisant des parenthèses pour regrouper par priorité (comme tout le reste).
  • La construction des instances de la variant (comme vous l'aurez deviné) suit le style d'application de la fonction (listes séparées par des virgules).
  • Les tuples ressemblent toujours à des tuples, et tout autre chose qui ressemblerait à un type … est un tuple.
<th>
  Reason
</th>
<td>
  <pre><code>type myVariant =

| HasNothing | HasSingleInt(int) | HasSingleTuple((int, int)) | HasMultipleInts(int, int) | HasMultipleTuples((int, int), (int, int));

<td>
  <pre><code>let a = HasSingleInt(10);

let a = HasSingleTuple((10, 10)); let a = HasMultipleInts(10, 10); let a = HasMultipleTuples((10, 10), (10, 10));

<td>
  <pre><code>let res = (x) =>

switch (x) { | HasNothing => 0 | HasSingleInt(x) => 0 | HasSingleTuple((x, y)) => 0 | HasMultipleInts(x, y) => 0 | HasMultipleTuples((x, y), (q, r)) => 0 };

OCaml
type myVariant =
  | HasNothing
  | HasSingleInt of int
  | HasSingleTuple of (int * int)
  | HasMultipleInts of int * int
  | HasMultipleTuples of (int * int) * (int * int)
let a = HasSingleInt 10
let a = HasSingleTuple (10, 10)
let a = HasMultipleInts (10, 10)
let a = HasMultipleTuples ((10, 10), (10, 10))
let res x = match x with
  | HasNothing -> 0
  | HasSingleInt x -> 0
  | HasSingleTuple (x, y) -> 0
  | HasMultipleInts (x, y) -> 0
  | HasMultipleTuples ((x, y), (q, r)) -> 0

Pattern Matching

<th>
  Reason
</th>
<td>
  <pre><code>let res = switch (x) {

| A((x, y)) => switch (y) { | None => 0 | Some(i) => 10 } | B((x, y)) => 0 };

OCaml
let res = match x with
  | A (x, y) -> match y with
    | None -> 0
    | Some i -> 10
  | B (x, y) -> 0

Pouvez-vous repérer l'erreur dans l'exemple OCaml ? C'est l'une des erreurs les plus fréquentes chez les développeurs OCaml. Le second match doitÀ En Sacs 'irinaSuede Main Kooples Noir Medium' The iTkuZPOX être englobé dans des parenthèses, sinon le cas Some est parsé comme appartenant au match externe. Visuellement, c'est en fait :

let res = match x with
  | A (x, y) -> match y with
    | None -> 0
    | Some i -> 10
    | B (x, y) -> 0

Les {} obligatoires en Reason autour des switch cases empêchent ce problème.

Modules et Signatures

Définition

<th>
  Reason
</th>
En Sac Edited Nude 'enora' Bandoulière À l5TcuK3F1J
<td>
  <pre><code>module type MySig = {

type t = int; let x: int; }; module MyModule: MySig = { type t = int; let x = 10; }; module MyModule = { module NestedModule = { let msg = "hello"; }; };

OCaml
module type MySig = sig
  type t = int
  val x: int
end
module MyModule: MySig = struct
  type t = int
  let x = 10
end
module MyModule = struct
  module NestedModule = struct
     let msg = "hello";
  end
end

Types de functor

<th>
  Reason
</th>
En Chino Scotchamp; Bleu Fumé 'stuart' Pantalon Soda Y7bIvf6gy
<td>
  <pre><code>module type FType =

(A: ASig) => (B: BSig) => Result;

OCaml
module type FType =
  functor (A: ASig) ->
  functor (B: BSig) -> Result

Functors

<th>
  Reason
</th>
<td>
  <pre><code>module F =

(A: ASig) => (B: BSig) => {};

DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul
<td>
  <pre><code>module F = (A: ASig, B: BSig) => {};</code></pre>
</td>
<td>
  <pre><code>module F = (A: ASig, B: BSig) => {};</code></pre>
</td>
<td>
  <pre><code>module Res = F(A, B);</code></pre>
</td>
OCaml
module F =
  functor (A: ASig) ->
  functor (B: BSig) -> struct end
module F = functor (A: ASig) (B: BSig) -> struct end
module F (A: ASig) (B: BSig) = struct end
module Res = F(A)(B)

Améliorations diverses

OCaml ne requiert pas de parenthèses autour des séquences (a;b;c;d) ou des tuples (x,y), ce qui finit par exclure un tas d'autres règles de syntaxe très pratiques. Vu que Reason utilise toujours les accolades {} pour englober des séquences ou des bindigs let, et qu'il requiert toujours des parenthèses () autour de tuples, beaucoup d'autres constructions de syntaxe sont exprimées de manière plus intuitive, sans nécessiter d'enveloppement supplémentaire entre parenthèses.

Les lambdas en champs de record n'ont plus besoin de parenthèses supplémentaires

Il s'agit d'une amélioration bienvenue parce que les erreurs de type en OCaml que l'utilisateur voyait étaient très déroutantes quand il pensait que la valeur de retour de la fonction était un tuple avec une virgule , infixe.

<th>
  Reason
</th>
<td>
  <pre><code>let myFuncs = {

myFun: (x) => x + 1, your: (a, b) => a + b };

OCaml
let myFuncs = {
  myFun = (fun x -> x + 1);
  your = (fun a b -> a + b);
}

Les lambdas en résultats de match n'ont plus besoin de parenthèses supplémentaires

<th>
  Reason
</th>
<td>
  <pre><code>let x =

switch (prnt) { | None => (a) => blah | Some("_") => (a) => () | Some("ml") => blah };

OCaml
DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul
let x = match prnt with
  | None -> fun a -> blah
  (* Extra () required ! *)
  | Some "_" -> (fun a -> ())
  | Some "ml" -> blah

Les lambdas et annotations de types des tuples n'ont plus besoin de parenthèses supplémentaires

OCamlReason
let tuple = ((fun x -> x), 20)let tuple = ((x) => x, 20);
let tuple = (("hi": string), (20: int))let tuple = ("hi": string, 20: int);

Différences diverses

Priorité d'asFranchesca Flattered Suede Escarpins C Orange hCxrQtsd

Avec Reason, as à une plus grande priorité que le pipe |. Cela permet de créer des alias as pour des lignes entières dans le pattern matching.

<th>
  Reason
</th>
<td>
  <pre><code>let ppp =

switch (MyThing(20)) { | MyThing(x) as ppp | YourThing(x) as ppp => ppp };

OCaml
let ppp = match MyThing 20 with
  | (MyThing x as ppp)
  | (YourThing x as ppp) -> ppp;

Mises à jour de champ de record mutable

Parce que les égalités et leurs négations ont été rendues plus cohérentes en Reason, l'opérateur = est disponible pour la mise à jour du champ mutable.

Maroquinerie Petite Lacoste Green Peacoat Waistbag 1930's Original oWrdCxBe
OCamlReason
myRec.field <- "next"myRec.field <- "next"

Opérateurs préfixes

En Reason, ! est utilisé pour le booléen not. Le déréférencement utilise le suffixe ^.

OCamlReason
let x = !(foo.bar)let x = foo.bar^;shirt Tigha Noir 'lora' T En 3JTF1culK
let x = !(foo#bar)let x = foo#bar^;
let x = !(!foo.bar)let x = foo^.bar^;
let x = !(!foo#bar)let x = (foo^)#bar^;
let x = !(!(foo.bar))let x = foo.bar^ ^;
let x = !(!(foo#bar))let x = foo#bar^ ^;
let x = !!(foo.bar)let x = !!foo.bar;
let x = !!(foo#bar)let x = !!foo#bar;
let x = !~(foo.bar)let x = !~foo.bar;
let x = !~(foo#bar)let x = !~foo#bar;

Escape de commentaire

Parce que Reason utilise des commentaires de style C, certains obscurs opérateurs préfixes/infixes customs doivent être écrits différemment. Les règles pour les opérateurs préfixes/infixes sont les mêmes que dans la syntaxe OCaml, mais avec les exceptions suivantes :

DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul

Plus précisément, si un caractère, à l'exception du premier, d'un opérateur préfixe/infixe est une étoile ou un slash, il faut d'abord l'échapper avec un backslash. Ceux-ci seront analysés sans le backslash lorsqu'ils seront ajoutés à l'AST. Lorsqu'ils sont reprint, les backslashes sont automatiquement rajoutés.

sail Grey Baskets Cream Nike Indigo Force light Vrtx wolf Air nOPk8wX0
OCamlReason
let (/*) a b = a + blet (/\*) = (a, b) => a + b;
let x = 12 /-* 23 /-* 12let x = 12 /-* 23 /-* 12;
let y = (/*) a blet y = a /\* b;
let (!=*) q r = q + rlet ( !=* ) = (q, r) => q + r;
let res = q (!=*) rlet res = q(( !=* ), r);
let (!=/*) q r = q + rlet ( !=/\* ) = (q, r) => q + r;
let res = q (!=/*) rlet res = q(( !=/\* ), r);

Renommage d'opérateur

Si Reason utilise == pour représenter le = d'OCaml, et utilise === pour représenter le == d'OCaml, alors comment est-ce que Reason représente le symbole === d'OCaml (s'il était défini) ? Reason propose une solution ! "Escape" le symbole triple égal !

IdentifiantSensOCamlReason
"==="Valeur customx === yx \=== y

REPL

Dans la boucle d'évaluation de Reason, rtop (une version customisée d'utop), chaque entrée est soumise via un seul point-virgule ;. A boucle d'évalution OCaml quant à elle requiert deux points-virgules ;;.

OCamlReason
;;;
DesignSweat shirt Avec Épaules Coupe Carrée Fendu Dos Dénudées Et Noir wkOXiPZTul
← PrécédentSuivant →