Valeurs

Une valeur est une donnée produite par l’évaluation d’une expression. Cette section décrit les genres de valeurs dans le langage M. Chaque genre de valeur est associé à une syntaxe littérale, un ensemble de valeurs qui sont de ce genre, un ensemble d’opérateurs définis sur cet ensemble de valeurs et un type intrinsèque attribué aux valeurs nouvellement construites.

Genre Littéral
Null null
Opérateurs logiques true    false
Nombre 0    1    -1    1.5    2.3e-5
Time #time(09,15,00)
Date #date(2013,02,26)
DateTime #datetime(2013,02,26, 09,15,00)
DateTimeZone #datetimezone(2013,02,26, 09,15,00, 09,00)
Durée #duration(0,1,30,0)
Texte "hello"
Binaire #binary("AQID")
Liste {1, 2, 3}
Enregistrement [ A = 1, B = 2 ]
Table #table({"X","Y"},{{0,1},{1,0}})
Fonction (x) => x + 1
Type type { number }    type table [ A = any, B = text ]

Les sections suivantes traitent de chaque genre de valeur en détail. Les types et les attributions de type sont définis de manière formelle dans Types. Les valeurs de fonction sont définies dans Fonctions. Les sections suivantes listent les opérateurs définis pour chaque genre de valeur et donnent des exemples. La définition complète de la sémantique d’opérateur suit dans Opérateurs.

Null

Une valeur Null est utilisée pour représenter l’absence de valeur ou une valeur à l’état indéterminé ou inconnu. Une valeur Null est écrite à l’aide du littéral null. Les opérateurs suivants sont définis pour les valeurs Null :

Opérateur Résultat
x > y Supérieur à
x >= y Supérieur ou égal à
x < y Inférieur à
x <= y Inférieur ou égal à
x = y Égal à
x <> y Différent de
x ?? y Coalesce

Le type natif de la valeur null est le type intrinsèque null.

Logical

Une valeur logique est utilisée pour les opérations booléennes ; elle a la valeur true ou false. Une valeur logique est écrite à l’aide des littéraux true et false. Les opérateurs suivants sont définis pour les valeurs logiques :

Opérateur Résultat
x > y Supérieur à
x >= y Supérieur ou égal à
x < y Inférieur à
x <= y Inférieur ou égal à
x = y Égal à
x <> y Différent de
x or y OR logique conditionnel
x ?? y Coalesce
x and y AND logique conditionnel
not x NOT logique

Le type natif des deux valeurs logiques (true et false) est le type intrinsèque logical.

Nombre

Une valeur Nombre est utilisée pour les opérations numériques et arithmétiques. Voici quelques exemples de littéraux de nombres :

3.14  // Fractional number 
-1.5  // Fractional number 
1.0e3 // Fractional number with exponent
123   // Whole number 
1e3   // Whole number with exponent 
0xff  // Whole number in hex (255)

Un nombre est représenté avec au moins la précision d’un double (mais peut conserver une plus grande précision). La représentation double est conforme à la norme IEEE double précision 64 bits pour l’arithmétique à virgule flottante binaire définie dans [IEEE 754-2008]. (La représentation double a une plage dynamique approximative comprise entre 5,0 x 10324 et 1,7 x 10308 avec une précision de 15-16 chiffres.)

Les valeurs spéciales suivantes sont également considérées comme des valeurs Nombre :

  • Zéro positif et zéro négatif. Dans la plupart des cas, le zéro positif et le zéro négatif se comportent de la même façon que la valeur simple zéro, mais certaines opérations font la distinction entre les deux.

  • Infini positif (#infinity) et infini négatif (-#infinity). Les infinis sont produits par des opérations telles que la division d’un nombre différent de zéro par zéro. Par exemple, 1.0 / 0.0 produit l’infini positif et -1.0 / 0.0 produit l’infini négatif.

  • La valeur N’est pas un nombre (#nan), souvent abrégée NaN (Not-a-Number). Les valeurs NaN sont produites par des opérations à virgule flottante non valides, telles que la division de zéro par zéro.

Les opérations mathématiques binaires sont effectuées à l’aide d’une précision. La précision détermine le domaine vers lequel les opérandes sont arrondis et le domaine dans lequel l’opération est effectuée. En l’absence de précision explicitement spécifiée, ces opérations sont effectuées à l’aide de double précision.

  • Si le résultat d’une opération mathématique est trop petit pour le format de destination, le résultat de l’opération devient un zéro positif ou un zéro négatif.

  • Si le résultat d’une opération mathématique est trop grand pour le format de destination, le résultat de l’opération devient l’infini positif ou l’infini négatif.

  • Si une opération mathématique n’est pas valide, le résultat de l’opération devient NaN.

  • Si l’un ou les deux opérandes d’une opération à virgule flottante sont NaN, le résultat de l’opération devient NaN.

Les opérateurs suivants sont définis pour les valeurs Nombre :

Opérateur Résultat
x > y Supérieur à
x >= y Supérieur ou égal à
x < y Inférieur à
x <= y Inférieur ou égal à
x = y Égal à
x <> y Différent de
x + y Somme
x - y Différence
x * y Produit
x / y Quotient
x ?? y Coalesce
+x Plus unaire
-x Négation

Le type natif des valeurs Nombre est le type intrinsèque number.

Heure

Une valeur Time stocke une représentation opaque de l’heure de la journée. Une heure est encodée sous la forme d’un nombre de cycles depuis minuit, qui compte le nombre de cycles de 100 nanosecondes qui se sont écoulés sur une horloge de 24 heures. Le nombre maximal de cycles depuis minuit correspond à 23:59:59,9999999 heures.

Bien qu’il n’existe aucune syntaxe littérale pour les heures, plusieurs fonctions de bibliothèque standard sont fournies pour les construire. Les valeurs d’heure peuvent également être construites à l’aide de la fonction intrinsèque #time :

#time(hour, minute, second)

Les conditions suivantes doivent être remplies, sinon une erreur avec le code de raison Expression.Error est générée :

0 ≤ hour ≤ 24
0 ≤ minute ≤ 59
0 ≤ seconde ≤ 59

De plus, si heure = 24, minute et seconde doivent être égales à zéro.

Les opérateurs suivants sont définis pour les valeurs Time :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x >= y Supérieur ou égal à
x > y Supérieur à
x < y Inférieur à
x <= y Inférieur ou égal à
x ?? y Coalesce

Les opérateurs suivants autorisent que l’un ou les deux opérandes soient une date :

Opérateur Opérande gauche Opérande droit Signification
x + y time duration Date décalée d’une durée
x + y duration time Date décalée d’une durée
x - y time duration Date décalée d’une durée négative
x - y time time Durée entre dates
x & y date time Datetime fusionné

Le type natif des valeurs Time est le type intrinsèque time.

Date

Une valeur Date stocke une représentation opaque d’un jour spécifique. Une date est encodée sous la forme d’un nombre de jours depuis l’époque, à partir du 1er janvier 0001 de l’ère commune sur le calendrier grégorien. Le nombre maximal de jours depuis l’époque est de 3652058, ce qui correspond au 31 décembre 9999.

Bien qu’il n’existe aucune syntaxe littérale pour les dates, plusieurs fonctions de bibliothèque standard sont fournies pour les construire. Les valeurs de dates peuvent également être construites à l’aide de la fonction intrinsèque #date :

#date(year, month, day)

Les conditions suivantes doivent être remplies, sinon une erreur avec le code de raison Expression.Error est générée :

1 ≤ year ≤ 9999
1 ≤ month ≤ 12
1 ≤ day ≤ 31

En outre, le jour doit être valide pour le mois et l’année choisis.

Les opérateurs suivants sont définis pour les valeurs Date :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x >= y Supérieur ou égal à
x > y Supérieur à
x < y Inférieur à
x <= y Inférieur ou égal à
x ?? y Coalesce

Les opérateurs suivants autorisent que l’un ou les deux opérandes soient une date :

Opérateur Opérande gauche Opérande droit Signification
x + y date duration Date décalée d’une durée
x + y duration date Date décalée d’une durée
x - y date duration Date décalée d’une durée négative
x - y date date Durée entre dates
x & y date time Datetime fusionné

Le type natif des valeurs Date est le type intrinsèque date.

Date/Heure

Une valeur DateTime contient à la fois une date et une heure.

Bien qu’il n’existe aucune syntaxe littérale pour DateHeure, plusieurs fonctions de bibliothèque standard sont fournies pour les construire. Les valeurs DateHeure peuvent également être construites à l’aide de la fonction intrinsèque #datetime :

#datetime(year, month, day, hour, minute, second)

Les conditions suivantes doivent être remplies, sinon une erreur avec le code de raison Expression.Error est générée : 1 ≤ year ≤ 9999
1 ≤ month ≤ 12
1 ≤ day ≤ 31
0 ≤ hour ≤ 23
0 ≤ minute ≤ 59
0 ≤ seconde ≤ 59

En outre, le jour doit être valide pour le mois et l’année choisis.

Les opérateurs suivants sont définis pour les valeurs DateTime :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x >= y Supérieur ou égal à
x > y Supérieur à
x < y Inférieur à
x <= y Inférieur ou égal à
x ?? y Coalesce

Les opérateurs suivants autorisent que l’un ou les deux opérandes soient une valeur DateTime :

Opérateur Opérande gauche Opérande droit Signification
x + y datetime duration Datetime décalé d’une durée
x + y duration datetime Datetime décalé d’une durée
x - y datetime duration Datetime décalé d’une durée négative
x - y datetime datetime Durée entre datetimes

Le type natif des valeurs DateTime est le type intrinsèque datetime.

DateTimeZone

Une valeur DateTimeZone contient une valeur DateTime et un fuseau horaire. Un fuseau horaire est encodé sous la forme d’un nombre de minutes de décalage par rapport à l’heure UTC, qui compte le nombre de minutes desquelles la partie heure de la valeur DateTime doit être décalée par rapport au temps universel coordonné (UTC, Universal Coordinated Time). Le nombre minimal de minutes de décalage par rapport à l’heure UTC est -840, ce qui représente un décalage UTC de -14:00, ou quatorze heures antérieures à l’heure UTC. Le nombre maximal de minutes de décalage par rapport à l’heure UTC est 840, ce qui correspond à un décalage UTC de 14:00.

Bien qu’il n’existe aucune syntaxe littérale pour datetimezones, plusieurs fonctions de bibliothèque standard sont fournies pour les construire. Les valeurs datetimezones peuvent également être construites à l’aide de la fonction intrinsèque #datetimezone :

#datetimezone(
       year, month, day,
       hour, minute, second,
       offset-hours, offset-minutes)

Les conditions suivantes doivent être remplies, sinon une erreur avec le code de raison Expression.Error est générée :

1 ≤ year ≤ 9999
1 ≤ month ≤ 12
1 ≤ day ≤ 31
0 ≤ hour ≤ 23
0 ≤ minute ≤ 59
0 ≤ seconde ≤ 59
-14 ≤ offset-hours ≤ 14
-59 ≤ offset-minutes ≤ 59

En outre, le jour doit être valide pour le mois et l’année choisis et, si offset-hours = 14, alors offset-minutes <= 0 et, si offset-hours = -14, alors offset-minutes >= 0.

Les opérateurs suivants sont définis pour les valeurs DateTimeZone :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x >= y Supérieur ou égal à
x > y Supérieur à
x < y Inférieur à
x <= y Inférieur ou égal à
x ?? y Coalesce

Les opérateurs suivants autorisent que l’un ou les deux opérandes soient une valeur DateTimeZone :

Opérateur Opérande gauche Opérande droit Signification
x + y datetimezone duration Datetimezone décalé d’une durée
x + y duration datetimezone Datetimezone décalé d’une durée
x - y datetimezone duration Datetimezone décalé d’une durée négative
x - y datetimezone datetimezone Durée entre datetimezones

Le type natif des valeurs DateTimeZone est le type intrinsèque datetimezone.

Durée

Une valeur Durée stocke une représentation opaque de la distance entre deux points sur une chronologie mesurée en cycles de 100 nanosecondes. La grandeur d’une durée peut être positive ou négative, les valeurs positives indiquant une progression vers l’avant dans le temps et les valeurs négatives indiquant une progression en arrière dans le temps. La valeur minimale qui peut être stockée dans une durée est de -9 223 372 036 854 775 808 cycles, soit 10 675 199 jours 2 heures 48 minutes 05,4775808 secondes en arrière dans le temps. La valeur maximale qui peut être stockée dans une durée est de 9 223 372 036 854 775 807 cycles, soit 10 675 199 jours 2 heures 48 minutes 05,4775807 secondes vers l’avant dans le temps.

Bien qu’il n’existe aucune syntaxe littérale pour les durées, plusieurs fonctions de bibliothèque standard sont fournies pour les construire. Les valeurs de durée peuvent également être construites à l’aide de la fonction intrinsèque #duration :

#duration(0, 0, 0, 5.5)          // 5.5 seconds 
#duration(0, 0, 0, -5.5)         // -5.5 seconds 
#duration(0, 0, 5, 30)           // 5.5 minutes 
#duration(0, 0, 5, -30)          // 4.5 minutes 
#duration(0, 24, 0, 0)           // 1 day 
#duration(1, 0, 0, 0)            // 1 day

Les opérateurs suivants sont définis sur les valeurs de durée :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x >= y Supérieur ou égal à
x > y Supérieur à
x < y Inférieur à
x <= y Inférieur ou égal à
x ?? y Coalesce

De plus, les opérateurs suivants autorisent que l’un ou les deux opérandes soient une valeur de durée :

Opérateur Opérande gauche Opérande droit Signification
x + y datetime duration Datetime décalé d’une durée
x + y duration datetime Datetime décalé d’une durée
x + y duration duration Somme de durées
x - y datetime duration Datetime décalé d’une durée négative
x - y datetime datetime Durée entre datetimes
x - y duration duration Différence de durées
x * y duration number N fois une durée
x * y number duration N fois une durée
x / y duration number Fraction d’une durée

Le type natif des valeurs de durée est le type intrinsèque duration.

Texte

Une valeur Texte représente une séquence de caractères Unicode. Les valeurs de texte ont une forme littérale conforme à la grammaire suivante :

_text-literal:
      " text-literal-charactersopt"
text-literal-characters :
      text-literal-character text-literal-charactersopt
text-literal-character :
      single-text-character
      character-escape-sequence
      double-quote-escape-sequence
single-text-character :

      Tout caractère sauf " (U+0022) ou # (U+0023) suivi de ( (U+0028)
double-quote-escape-sequence:
      "" (U+0022, U+0022)

Voici un exemple de valeur Texte :

"ABC" // the text value ABC

Les opérateurs suivants sont définis pour les valeurs Texte :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x >= y Supérieur ou égal à
x > y Supérieur à
x < y Inférieur à
x <= y Inférieur ou égal à
x & y Concaténation
x ?? y Coalesce

Le type natif des valeurs de texte est le type intrinsèque text.

Binaire

Une valeur binaire représente une séquence d’octets.

Bien qu’il n’existe aucune syntaxe littérale pour les valeurs binaires, plusieurs fonctions de bibliothèque standard sont fournies pour les construire. Les valeurs binaires peuvent également être construites à l’aide de la fonction intrinsèque #binary.

Voici un exemple de valeur binaire construite à partir d’une liste d’octets :

#binary( {0x00, 0x01, 0x02, 0x03} )

Les opérateurs suivants sont définis pour les valeurs binaires :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x >= y Supérieur ou égal à
x > y Supérieur à
x < y Inférieur à
x <= y Inférieur ou égal à
x ?? y Coalesce

Le type natif des valeurs binaires est le type intrinsèque binary.

Liste

Une valeur Liste est une valeur qui produit une séquence de valeurs en cas d’énumération. Une valeur produite par une liste peut contenir n’importe quel genre de valeur, y compris une liste. Vous pouvez construire des listes à l’aide de la syntaxe d’initialisation comme suit :

list-expression:
      { item-listopt }
item-list :
      item
      item
,item-list
item :
      expression
      expression
..expression

Voici un exemple de list-expression qui définit une liste avec trois valeurs de texte : "A", "B" et "C".

{"A", "B", "C"}

La valeur "A" est le premier élément de la liste et la valeur "C" est le dernier élément de la liste.

  • Les éléments d’une liste ne sont pas évalués tant qu’ils ne sont pas sollicités.
  • Bien que les valeurs de liste construites à l’aide de la syntaxe de liste produisent des éléments dans l’ordre dans lequel elles apparaissent dans item-list, en général, les listes retournées à partir de fonctions de bibliothèque peuvent produire un ensemble différent ou un nombre différent de valeurs chaque fois qu’elles sont énumérées.

Pour inclure une séquence de nombres entiers dans une liste, vous pouvez utiliser la forme a..b :

{ 1, 5..9, 11 }     // { 1, 5, 6, 7, 8, 9, 11 }

Le nombre d’éléments dans une liste, appelé list count, peut être déterminé à l’aide de la fonction List.Count.

List.Count({true, false})  // 2 
List.Count({})             // 0

Une liste peut effectivement avoir un nombre infini d’éléments ; la fonction List.Count pour ces listes n’est pas définie et peut générer une erreur ou ne pas se terminer.

Si une liste ne contient aucun élément, elle est appelée liste vide. Une liste vide est écrite sous la forme suivante :

{}  // empty list

Les opérateurs suivants sont définis pour les listes :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x & y Concatenate
x ?? y Coalesce

Par exemple :

{1, 2} & {3, 4, 5}   // {1, 2, 3, 4, 5} 
{1, 2} = {1, 2}      // true 
{2, 1} <> {1, 2}     // true

Le type natif des valeurs de liste est le type intrinsèque list, qui spécifie un type d’élément any.

Enregistrement

Une valeur Enregistrement est une séquence ordonnée de champs. Un champ est constitué d’un nom de champ, qui est une valeur de texte qui identifie de façon unique le champ dans l’enregistrement, et d’une valeur de champ. La valeur de champ peut être n’importe quel genre de valeur, y compris un enregistrement. Les enregistrements peuvent être construits à l’aide de la syntaxe d’initialisation comme suit :

record-expression:
      [field-listopt]
field-list :
      field
      field
,field-list
field :
      field-name
=expression
field-name :
      generalized-identifier
      quoted-identifier

L’exemple suivant construit un enregistrement avec un champ nommé x avec la valeur 1, et un champ nommé y avec la valeur 2.

[ x = 1, y = 2 ]

L’exemple suivant construit un enregistrement avec un champ a nommé a avec une valeur d’enregistrement imbriquée. L’enregistrement imbriqué contient un champ nommé b avec la valeur 2.

[ a = [ b = 2 ] ]

Les comportements suivants s’appliquent lors de l’évaluation d’une expression d’enregistrement :

  • L’expression assignée à chaque nom de champ est utilisée pour déterminer la valeur du champ associé.

  • Si l’expression assignée à un nom de champ produit une valeur lors de l’évaluation, cette valeur devient la valeur du champ de l’enregistrement résultant.

  • Si l’expression assignée à un nom de champ génère une erreur quand elle est évaluée, le fait qu’une erreur ait été générée est enregistré avec le champ, en plus de la valeur d’erreur générée. L’accès ultérieur à ce champ provoquera la nouvelle génération d’une erreur avec la valeur d’erreur enregistrée.

  • L’expression est évaluée dans un environnement tel que l’environnement parent uniquement avec des variables fusionnées qui correspondent à la valeur de chaque champ de l’enregistrement, à l’exception de celui qui est initialisé.

  • Une valeur dans un enregistrement n’est pas évaluée tant que le champ correspondant n’est pas sollicité.

  • Une valeur dans un enregistrement est évaluée au plus une fois.

  • Le résultat de l’expression est une valeur d’enregistrement avec un enregistrement de métadonnées vide.

  • L’ordre des champs dans l’enregistrement est défini par l’ordre dans lequel ils apparaissent dans record-initializer-expression.

  • Chaque nom de champ spécifié doit être unique dans l’enregistrement, sinon il s’agit d’une erreur. Les noms sont comparés à l’aide d’une comparaison ordinale.

    [ x = 1, x = 2 ] // error: field names must be unique 
    [ X = 1, x = 2 ] // OK

Un enregistrement sans champ est appelé enregistrement vide et écrit comme suit :

[] // empty record

Bien que l’ordre des champs d’un enregistrement ne soit pas significatif lors de l’accès à un champ ou de la comparaison de deux enregistrements, il est significatif dans d’autres contextes, par exemple quand les champs d’un enregistrement sont énumérés.

Les deux mêmes enregistrements produisent des résultats différents quand les champs sont obtenus :

Record.FieldNames([ x = 1, y = 2 ]) // [ "x", "y" ] 
Record.FieldNames([ y = 1, x = 2 ]) // [ "y", "x" ]

Le nombre de champs dans un enregistrement peut être déterminé à l’aide de la fonction Record.FieldCount. Par exemple :

Record.FieldCount([ x = 1, y = 2 })  // 2 
Record.FieldCount([])                // 0

Outre l’utilisation de la syntaxe d’initialisation d’enregistrement [ ], les enregistrements peuvent être construits à partir d’une liste de valeurs, et d’une liste de noms de champs ou un type d’enregistrement. Par exemple :

Record.FromList({1, 2}, {"a", "b"})

Ce qui équivaut à :

[ a = 1, b = 2 ]

Les opérateurs suivants sont définis pour les valeurs d’enregistrement :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x & y Fusionner
x ?? y Coalesce

Les exemples suivants illustrent l’utilisation des opérateurs ci-dessus. Notez que la fusion d’enregistrements utilise les champs de l’opérande droit pour remplacer les champs de l’opérande gauche dans le cas où les noms de champs se chevauchent.

[ a = 1, b = 2 ] & [ c = 3 ]    // [ a = 1, b = 2, c = 3 ] 
[ a = 1, b = 2 ] & [ a = 3 ]    // [ a = 3, b = 2 ] 
[ a = 1, b = 2 ] = [ b = 2, a = 1 ]         // true 
[ a = 1, b = 2, c = 3 ] <> [ a = 1, b = 2 ] // true

Le type natif des valeurs d’enregistrement est le type intrinsèque record, qui spécifie une liste de champs vide ouverte.

Table

Une valeur Table est une séquence ordonnée de lignes. Une ligne est une séquence ordonnée de valeurs de colonne. Le type de la table détermine la longueur de toutes les lignes de la table, les noms des colonnes de la table, les types des colonnes de la table et la structure des clés de la table (le cas échéant).

Bien qu’il n’existe aucune syntaxe littérale pour les tables, plusieurs fonctions de bibliothèque standard sont fournies pour les construire. Les tables peuvent également être construites à l’aide de la fonction intrinsèque #table.

Voici un exemple de table construite à partir d’une liste de noms de colonnes et d’une liste de lignes. La table obtenue contient deux colonnes de type any et trois lignes.

#table({"x", "x^2"}, {{1,1}, {2,4}, {3,9}})

Vous pouvez aussi utiliser #table pour spécifier un type de table complet :

#table(
    type table [Digit = number, Name = text],  
    {{1,"one"}, {2,"two"}, {3,"three"}} 
    )

Ici, la nouvelle valeur de table a un type de table qui spécifie des noms de colonnes et des types de colonnes.

Les opérateurs suivants sont définis pour les valeurs de table :

Opérateur Résultat
x = y Égal à
x <> y Différent de
x & y Concaténation
x ?? y Coalesce

La concaténation de tables aligne les colonnes de même nom et insère la valeur null pour les colonnes qui apparaissent dans une seule des tables d’opérandes. L’exemple suivant illustre la concaténation de tables :

  #table({"A","B"}, {{1,2}}) 
& #table({"B","C"}, {{3,4}})
A B C
1 2 null
null 3 4

Le type natif des valeurs de table est un type de table personnalisé (dérivé du type intrinsèque table) qui liste les noms de colonnes, spécifie tous les types de colonnes comme étant « any », et n’a pas de clé. (Pour plus d’informations sur les types de tables, consultez Types de tables.)

Fonction

Une valeur Fonction est une valeur qui mappe un jeu d’arguments à une valeur unique. Les détails des valeurs de fonction sont décrits dans Fonctions.

Type

Une valeur Type est une valeur qui classifie d’autres valeurs. Les détails des valeurs de type sont décrits dans Types.