Valori

Un valore è un dato prodotto dalla valutazione di un'espressione. In questa sezione vengono descritti i tipi di valori disponibili nel linguaggio M. Ogni tipo di valore è associato a una sintassi letterale, a un set di valori dello stesso tipo, a un set di operatori definiti per il set di valori e a un tipo intrinseco attribuito ai valori appena creati.

Tipologia Literal
Null null
Logico true    false
Numero 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)
Durata #duration(0,1,30,0)
Text "hello"
Binario #binary("AQID")
Elenco {1, 2, 3}
Record [ A = 1, B = 2 ]
Tabella #table({"X","Y"},{{0,1},{1,0}})
Funzione (x) => x + 1
Tipo type { number }    type table [ A = any, B = text ]

Nelle sezioni seguenti viene descritto in dettaglio ogni tipo di valore. I tipi e le relative attribuzioni vengono definiti formalmente nella sezione Tipi, mentre i valori di funzione vengono definiti nella sezione Funzioni. Nelle sezioni seguenti vengono inoltre elencati gli operatori definiti per ogni tipo di valore e vengono forniti alcuni esempi. La definizione completa della semantica degli operatori è disponibile nella sezione Operatori.

Null

Con un valore Null si rappresenta l'assenza di un valore o un valore con uno stato indeterminato o sconosciuto. Un valore Null viene scritto usando il valore letterale null. Per i valori Null vengono definiti gli operatori seguenti:

Operatore Risultato
x > y Maggiore di
x >= y Maggiore di o uguale a
x < y Minore di
x <= y Minore di o uguale a
x = y Equal
x <> y Not equal
x ?? y Coalesce

Il tipo nativo del valore null è il tipo intrinseco null.

Logico

Un valore logico viene usato per le operazioni booleane e può avere il valore true o false. Un valore logico viene scritto usando i valori letterali true e false. Per i valori logici vengono definiti gli operatori seguenti:

Operatore Risultato
x > y Maggiore di
x >= y Maggiore di o uguale a
x < y Minore di
x <= y Minore di o uguale a
x = y Equal
x <> y Not equal
x or y OR logico condizionale
x ?? y Coalesce
x and y AND logico condizionale
not x NOT logico

Il tipo nativo di entrambi i valori logici (true e false) è il tipo intrinseco logical.

Numero

Un valore numero viene usato per le operazioni numeriche e aritmetiche. Di seguito sono riportati alcuni esempi di valori letterali numerici:

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 numero viene rappresentato con almeno la precisione doppia (ma può presentare anche una precisione maggiore). La rappresentazione doppia è conforme allo standard di precisione doppia IEEE 64 bit per l'aritmetica a virgola mobile binaria definita in [IEEE 754-2008]. La rappresentazione doppia presenta un intervallo dinamico approssimativo compreso tra 5 x 10324 e 1,7 x 10308 con una precisione di 15-16 cifre.

Sono considerati valori numero anche i valori speciali seguenti:

  • Zero positivo e zero negativo. Nella maggior parte dei casi, zero positivo e zero negativo si comportano in modo identico al semplice valore zero, sebbene alcune operazioni facciano distinzione tra i due valori.

  • Infinito positivo (#infinity) e infinito negativo (-#infinity). Gli infiniti sono prodotti da operazioni quali la divisione di un numero diverso da zero per zero. 1.0 / 0.0 restituisce ad esempio un infinito positivo, mentre -1.0 / 0.0 restituisce un infinito negativo.

  • Il valore Not-a-Number (#nan), spesso abbreviato con NaN. I valori NaN sono prodotti da operazioni a virgola mobile non valide, come la divisione di zero per zero.

Le operazioni matematiche binarie vengono eseguite usando una precisione, che determina il dominio in cui vengono arrotondati gli operandi e il dominio in cui viene eseguita l'operazione. In assenza di una precisione specificata in modo esplicito, queste operazioni vengono eseguite usando la precisione doppia.

  • Se il risultato di un'operazione matematica è troppo piccolo per il formato di destinazione, il risultato dell'operazione diventa zero positivo o zero negativo.

  • Se il risultato di un'operazione matematica è troppo grande per il formato di destinazione, il risultato dell'operazione diventa un infinito positivo o un infinito negativo.

  • Se un'operazione matematica non è valida, il risultato dell'operazione diventa NaN.

  • Se uno o entrambi gli operandi di un'operazione a virgola mobile è NaN, il risultato dell'operazione diventa NaN.

Per i valori numero vengono definiti gli operatori seguenti:

Operatore Risultato
x > y Maggiore di
x >= y Maggiore di o uguale a
x < y Minore di
x <= y Minore di o uguale a
x = y Equal
x <> y Not equal
x + y Sum
x - y Differenza
x * y Prodotto
x / y Quoziente
x ?? y Coalesce
+x Più unario
-x Negazione

Il tipo nativo dei valori numero è il tipo intrinseco number.

Time

Nel valore ora viene archiviata una rappresentazione opaca dell'ora del giorno. Un valore ora viene codificato come il numero di tick dalla mezzanotte, ovvero come il numero di tick da 100 nanosecondi trascorsi nel formato 24 ore. Il numero massimo di tick dalla mezzanotte corrisponde a 23:59:59,9999999 ore.

Sebbene non esista una sintassi letterale per i valori ora, per crearli sono disponibili varie funzioni della libreria standard. I valori ora possono essere creati anche usando la funzione intrinseca #time:

#time(hour, minute, second)

Devono essere rispettati gli intervalli seguenti; in caso contrario, viene generato un errore con il codice motivo Expression.Error.

0 ≤ ora ≤ 24
0 ≤ minuto ≤ 59
0 ≤ secondo ≤ 59

Inoltre, se ora = 24, il minuto e il secondo devono essere pari a zero.

Per i valori ora vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x >= y Maggiore di o uguale a
x > y Maggiore di
x < y Minore di
x <= y Minore di o uguale a
x ?? y Coalesce

Gli operatori seguenti consentono a uno o a entrambi gli operandi di essere una data:

Operatore Operando sinistro Operando destro Significato
x + y time duration Offset della data in base alla durata
x + y duration time Offset della data in base alla durata
x - y time duration Offset della data in base alla durata negata
x - y time time Durata tra date
x & y date time Valore datetime unito

Il tipo nativo dei valori ora è il tipo intrinseco time.

Data

Nel valore data viene archiviata una rappresentazione opaca di un giorno specifico. Un valore data viene codificato come numero di giorni trascorsi dalla data epoch, partendo dal 1° gennaio 0001 DC sul calendario gregoriano. Il numero massimo di giorni trascorsi dalla data epoch è 3.652.058, corrispondente al 31 dicembre 9999.

Sebbene non esista una sintassi letterale per le date per crearle sono disponibili varie funzioni della libreria standard. Le date possono essere create anche usando la funzione intrinseca #date:

#date(year, month, day)

Devono essere rispettati gli intervalli seguenti; in caso contrario, viene generato un errore con il codice motivo Expression.Error.

1 ≤ anno ≤ 9999
1 ≤ mese ≤ 12
1 ≤ giorno ≤ 31

Inoltre, il giorno deve essere valido per il mese e l'anno scelti.

Per i valori data vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x >= y Maggiore di o uguale a
x > y Maggiore di
x < y Minore di
x <= y Minore di o uguale a
x ?? y Coalesce

Gli operatori seguenti consentono a uno o a entrambi gli operandi di essere una data:

Operatore Operando sinistro Operando destro Significato
x + y date duration Offset della data in base alla durata
x + y duration date Offset della data in base alla durata
x - y date duration Offset della data in base alla durata negata
x - y date date Durata tra date
x & y date time Valore datetime unito

Il tipo nativo dei valori data è il tipo intrinseco date.

Data/Ora

Un valore datetime contiene una data e un'ora.

Sebbene non esista una sintassi letterale per i valori datetime, per crearli sono disponibili varie funzioni della libreria standard. I valori datetime possono essere creati anche usando la funzione intrinseca #datetime:

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

Devono essere rispettati gli intervalli seguenti; in caso contrario, viene generato un errore con il codice motivo Expression.Error: 1 ≤ anno ≤ 9999
1 ≤ mese ≤ 12
1 ≤ giorno ≤ 31
0 ≤ ora ≤ 23
0 ≤ minuto ≤ 59
0 ≤ secondo ≤ 59

Inoltre, il giorno deve essere valido per il mese e l'anno scelti.

Per i valori datetime vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x >= y Maggiore di o uguale a
x > y Maggiore di
x < y Minore di
x <= y Minore di o uguale a
x ?? y Coalesce

Gli operatori seguenti consentono a uno o a entrambi gli operandi di essere un valore datetime:

Operatore Operando sinistro Operando destro Significato
x + y datetime duration Offset di datetime in base alla durata
x + y duration datetime Offset di datetime in base alla durata
x - y datetime duration Offset di datetime in base alla durata negata
x - y datetime datetime Durata tra valori datetime

Il tipo nativo dei valori datetime è il tipo intrinseco datetime.

DateTimeZone

Un valore datetimezone contiene un valore datetime e un fuso orario. Un fuso orario viene codificato come offset dei minuti dall'ora UTC, ovvero come il numero di minuti relativi all'offset della parte ora di datetime rispetto all'ora UTC (Universal Coordinated Time). La quantità minima di offset dei minuti rispetto a UTC è -840, che rappresenta un offset da UTC pari a -14:00, ovvero quattordici ore prima dell'ora UTC. La quantità massima di offset dei minuti rispetto a UTC è 840, che corrisponde a un offset da UTC pari a 14:00.

Sebbene non esista una sintassi letterale per i valori datetimezone, per crearli sono disponibili varie funzioni della libreria standard. I valori datetimezone possono essere creati anche usando la funzione intrinseca #datetimezone:

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

Devono essere rispettati gli intervalli seguenti; in caso contrario, viene generato un errore con il codice motivo Expression.Error.

1 ≤ anno ≤ 9999
1 ≤ mese ≤ 12
1 ≤ giorno ≤ 31
0 ≤ ora ≤ 23
0 ≤ minuto ≤ 59
0 ≤ secondo ≤ 59
-14 ≤ ore-offset ≤ 14
-59 ≤ minuti-offset ≤ 59

Inoltre, il giorno deve essere valido per il mese e l'anno scelti e, se ore-offset = 14, allora minuti-offset < = 0 e, se ore-offset = -14, allora minuti-offset > = 0.

Per i valori datetimezone vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x >= y Maggiore di o uguale a
x > y Maggiore di
x < y Minore di
x <= y Minore di o uguale a
x ?? y Coalesce

Gli operatori seguenti consentono a uno o a entrambi gli operandi di essere un valore datetimezone:

Operatore Operando sinistro Operando destro Significato
x + y datetimezone duration Offset di datetimezone in base alla durata
x + y duration datetimezone Offset di datetimezone in base alla durata
x - y datetimezone duration Offset di datetimezone in base alla durata negata
x - y datetimezone datetimezone Durata tra valori datetimezone

Il tipo nativo dei valori datetimezone è il tipo intrinseco datetimezone.

Durata

In un valore durata viene archiviata una rappresentazione opaca della distanza tra due punti in una sequenza temporale di tick da 100 nanosecondi. L'entità di una durata può essere positiva o negativa, con i valori positivi che indicano l'avanzamento in avanti nel tempo e i valori negativi che indicano l'avanzamento indietro nel tempo. Il valore minimo che può essere archiviato in una durata è -9.223.372.036.854.775.808 tick ovvero 10.675.199 giorni, 2 ore, 48 minuti e 05,4775808 secondi indietro nel tempo. Il valore massimo che può essere archiviato in una durata è 9.223.372.036.854.775.807 tick ovvero 10.675.199 giorni, 2 ore, 48 minuti e 05,4775807 secondi in avanti nel tempo.

Sebbene non esista una sintassi letterale per i valori di durata, per crearli sono disponibili varie funzioni della libreria standard. I valori di durata possono essere creati anche usando la funzione intrinseca #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

Per i valori durata vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x >= y Maggiore di o uguale a
x > y Maggiore di
x < y Minore di
x <= y Minore di o uguale a
x ?? y Coalesce

Gli operatori seguenti, inoltre, consentono a uno o a entrambi gli operandi di essere un valore durata:

Operatore Operando sinistro Operando destro Significato
x + y datetime duration Offset di datetime in base alla durata
x + y duration datetime Offset di datetime in base alla durata
x + y duration duration Somma delle durate
x - y datetime duration Offset di datetime in base alla durata negata
x - y datetime datetime Durata tra valori datetime
x - y duration duration Differenza tra le durate
x * y duration number N volte una durata
x * y number duration N volte una durata
x / y duration number Frazione di una durata

Il tipo nativo dei valori durata è il tipo intrinseco duration.

Testo

Un valore testo rappresenta una sequenza di caratteri Unicode. I valori testo presentano un formato letterale conforme alla grammatica seguente:

_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:

      Qualsiasi carattere ad eccezione di " (U+0022) o # (U+0023), seguito da ( (U+0028)
double-quote-escape-sequence:
      "" (U+0022, U+0022)

Di seguito è riportato un esempio di un valore testo:

"ABC" // the text value ABC

Per i valori testo vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x >= y Maggiore di o uguale a
x > y Maggiore di
x < y Minore di
x <= y Minore di o uguale a
x & y Concatenation
x ?? y Coalesce

Il tipo nativo dei valori testo è il tipo intrinseco text.

Binario

Un valore binario rappresenta una sequenza di byte,

Sebbene non esista una sintassi letterale per i valori binari, per crearli sono disponibili varie funzioni della libreria standard. I valori binari possono essere creati anche usando la funzione intrinseca #binary.

Nell'esempio seguente viene creato un valore binario da un elenco di byte:

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

Per i valori binari vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x >= y Maggiore di o uguale a
x > y Maggiore di
x < y Minore di
x <= y Minore di o uguale a
x ?? y Coalesce

Il tipo nativo dei valori binari è il tipo intrinseco binary.

List

Un valore elenco è un valore che produce una sequenza di valori nel momento in cui vengono enumerati. Un valore prodotto da un elenco può contenere qualsiasi tipo di valore, incluso un elenco. È possibile creare un elenco usando la sintassi di inizializzazione, come indicato di seguito:

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

Di seguito è riportato un esempio di list-expression che definisce un elenco con tre valori di testo: "A", "B" e "C".

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

Il valore "A" è il primo elemento dell'elenco, il valore "C" è l'ultimo.

  • Solo nel momento in cui si accede agli elementi di un elenco è possibile valutarli.
  • Mentre dai valori elenco creati usando la sintassi elenco, gli elementi vengono generati nell'ordine in cui appaiono in item-list, in generale, gli elenchi restituiti dalle funzioni di libreria possono produrre un set o un numero diverso di valori ogni volta che vengono enumerati.

Per includere una sequenza di numeri interi in un elenco, è possibile usare il formato a..b:

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

Il numero di elementi in un elenco, definito anche conteggio elenco, può essere determinato tramite la funzione List.Count.

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

Un elenco, di fatto, può avere un numero infinito di elementi; per questi elenchi, il valore List.Count non è definito ed è possibile che generi un errore o che non venga terminato.

Se un elenco non contiene elementi, viene definito elenco vuoto. Un elenco vuoto viene scritto come segue:

{}  // empty list

Per gli elenchi vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x & y Concatenate
x ?? y Coalesce

Ad esempio:

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

Il tipo nativo dei valori elenco è il tipo intrinseco list, che specifica un elemento di tipo any.

Registra

Un valore record è una sequenza ordinata di campi. Un campo è costituito da un nome campo, ovvero un valore di testo che identifica in modo univoco il campo all'interno del record, e da un valore campo. Il valore di un campo può essere di qualsiasi tipo, incluso un record. È possibile creare un record usando la sintassi di inizializzazione, come indicato di seguito:

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

Nell'esempio seguente viene creato un record con un campo denominato x con valore 1 e un campo denominato y con valore 2.

[ x = 1, y = 2 ]

Nell'esempio seguente viene creato un record con un campo denominato a con un valore di record annidato. Il record annidato include un campo denominato b con valore 2.

[ a = [ b = 2 ] ]

Quando si valuta l'espressione di un record, sono valide le considerazioni seguenti:

  • L'espressione assegnata a ogni nome di campo consente di determinare il valore del campo associato.

  • Se l'espressione assegnata a un nome di campo produce un valore quando viene valutata, il valore prodotto diventa il valore del campo del record risultante.

  • Se l'espressione assegnata a un nome di campo genera un errore quando viene valutata, insieme al campo viene registrata anche la presenza di un errore e il valore dell'errore generato. Al successivo accesso al campo, verrà nuovamente generato un errore, insieme al valore dell'errore registrato.

  • L'espressione viene valutata in un ambiente simile all'ambiente padre in cui sono unite solo le variabili, che corrispondono al valore di ogni campo del record, ad eccezione di quello inizializzato.

  • Un valore in un record non viene valutato fino a quando non si accede al campo corrispondente.

  • Il valore di un record non può essere valutato più di una volta.

  • Il risultato dell'espressione è un valore record con un record di metadati vuoto.

  • L'ordine dei campi all'interno del record viene definito in base all'ordine in cui appaiono in record-initializer-expression.

  • Ogni nome di campo specificato deve essere univoco all'interno del record; in caso contrario, è un errore. I nomi vengono confrontati usando un confronto ordinale.

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

Un record senza campi prende il nome record vuoto e viene scritto come segue:

[] // empty record

Anche se l'ordine dei campi di un record non è significativo quando si accede a un campo o si confrontano due record, è significativo in altri contesti, ad esempio quando vengono enumerati i campi di un record.

Gli stessi due record producono risultati diversi quando vengono ottenuti i campi:

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

Il numero di campi in un record può essere determinato tramite la funzione Record.FieldCount. Ad esempio:

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

È possibile creare i record non solo usando la sintassi di inizializzazione dei record [ ], ma anche da un elenco di valori e un elenco di nomi di campo o un tipo record. Ad esempio:

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

L'espressione precedente è equivalente a:

[ a = 1, b = 2 ]

Per i valori record vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x & y Unire
x ?? y Coalesce

Negli esempi seguenti vengono illustrati gli operatori precedenti. In caso di sovrapposizione nei nomi dei campi, il record Unione usa i campi dell'operando di destra per eseguire l'override dei campi dell'operando di sinistra.

[ 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

Il tipo nativo dei valori record è il tipo intrinseco record, che specifica un elenco vuoto e aperto di campi.

Tabella

Un valore tabella è una sequenza ordinata di righe. Un riga è una sequenza ordinata di valori di colonna. Il tipo tabella determina la lunghezza di tutte le righe della tabella, i nomi delle colonne della tabella, i tipi delle colonne della tabella e la struttura delle chiavi della tabella, se presenti.

Sebbene non esista una sintassi letterale per le tabelle, per crearle sono disponibili varie funzioni della libreria standard. Le tabelle possono essere create anche usando la funzione intrinseca #table.

L'esempio seguente crea una tabella da un elenco di nomi di colonna e da un elenco di righe. La tabella risultante conterrà due colonne di type any e tre righe.

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

#table può essere usato anche per specificare un tipo tabella completa:

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

In questo caso, il nuovo valore di tabella include un tipo tabella che specifica i nomi e i tipi di colonna.

Per i valori tabella vengono definiti gli operatori seguenti:

Operatore Risultato
x = y Equal
x <> y Not equal
x & y Concatenation
x ?? y Coalesce

La concatenazione di tabella allinea le colonne con nomi simili e inserisce null nelle colonne che appaiono in un'unica tabella degli operandi. Nell'esempio seguente viene illustrata la concatenazione di tabella:

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

Il tipo nativo dei valori di tabella è un tipo tabella personalizzato (derivato dal tipo intrinseco table) che elenca i nomi delle colonne e specifica che le tabelle possono essere di qualsiasi tipo e che non sono presenti chiavi. Per informazioni dettagliate sui tipi tabella, vedere Tipi tabella.

Funzione

Un valore funzione è un valore che esegue il mapping di un set di argomenti a un singolo valore. I dettagli dei valori funzione sono descritti nella sezione Funzioni.

Digita

Un valore tipo è un valore che classifica altri valori. I dettagli dei valori tipo sono descritti nella sezione Tipi.