Valores

Un valor son los datos que se generan al evaluar una expresión. En esta sección se describen los tipos de valores del lenguaje M. Cada tipo de valor está asociado a una sintaxis literal, un conjunto de valores de ese tipo, un conjunto de operadores definidos sobre ese conjunto de valores y un tipo intrínseco asignado a los valores recién construidos.

Tipo Literal
Null null
lógicos true    false
Number 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)
Duration #duration(0,1,30,0)
Texto "hello"
Binario #binary("AQID")
Lista {1, 2, 3}
Registro [ A = 1, B = 2 ]
Tabla #table({"X","Y"},{{0,1},{1,0}})
Function (x) => x + 1
Tipo type { number }    type table [ A = any, B = text ]

En las secciones siguientes se describe con detalle cada tipo de valor. Los tipos y atribución de tipos se definen formalmente en Tipos. Los valores de función se definen en Funciones. En las secciones siguientes se enumeran los operadores definidos para cada tipo de valor y se proporcionan ejemplos. La definición completa de la semántica de los operadores continúa en Operadores.

Null

Un valor NULL se usa para representar la ausencia de un valor, o bien un valor indeterminado o desconocido. Un valor NULL se escribe mediante el literal null. Los operadores siguientes se definen para los valores NULL:

Operador Resultado
x > y Mayor que
x >= y Mayor o igual que
x < y Menor que
x <= y Menor o igual que
x = y Igual
x <> y No igual a
x ?? y Coalesce

El tipo nativo del valor null es el tipo intrínseco null.

Lógico

Un valor lógico se usa para las operaciones booleanas y tiene el valor true o false. Un valor lógico se escribe mediante los literales true y false. Los operadores siguientes se definen para los valores lógicos:

Operador Resultado
x > y Mayor que
x >= y Mayor o igual que
x < y Menor que
x <= y Menor o igual que
x = y Igual
x <> y No igual a
x or y OR lógico condicional
x ?? y Coalesce
x and y AND lógico condicional
not x NOT lógico

El tipo nativo de los dos valores lógicos (true y false) es el tipo intrínseco logical.

Número

Se usa un valor número para las operaciones numéricas y aritméticas. Los siguientes son ejemplos de literales de número:

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 número se representa con al menos la precisión de un doble (pero puede conservar más precisión). La representación doble es congruente con el estándar de precisión doble de 64 bits de IEEE para la aritmética de punto flotante binaria definida en [IEEE 754-2008]. (La representación doble tiene un intervalo dinámico aproximado de 5,0 x 10324 a 1,7 x 10308 con una precisión de 15-16 dígitos).

Los valores especiales siguientes también se consideran valores número:

  • Cero positivo y cero negativo. En la mayoría de los casos, cero positivo y cero negativo se comportan exactamente igual que el valor cero simple, pero ciertas operaciones distinguen entre ambos.

  • Infinito positivo (#infinity) e infinito negativo (-#infinity). Los infinitos se generan mediante operaciones como la división por cero de un número distinto de cero. Por ejemplo, 1.0 / 0.0 produce infinito positivo y -1.0 / 0.0 produce infinito negativo.

  • El valor No es un número (#nan), a menudo abreviado como NaN. Los Nan se generan mediante operaciones de punto flotante no válidas, como la división de cero por cero.

Las operaciones matemáticas binarias se realizan mediante una precisión. La precisión determina el dominio al que se redondean los operandos y el dominio en el que se realiza la operación. En ausencia de una precisión especificada de forma explícita, estas operaciones se realizan con precisión doble.

  • Si el resultado de una operación matemática es demasiado pequeño para el formato de destino, el resultado de la operación se convierte en cero positivo o cero negativo.

  • Si el resultado de una operación matemática es demasiado grande para el formato de destino, el resultado de la operación se convierte en infinito positivo o infinito negativo.

  • Si una operación matemática no es válida, el resultado de la operación se convierte en NaN.

  • Si uno o los dos operandos de una operación de punto flotante son NaN, el resultado de la operación se convierte en NaN.

Los operadores siguientes se definen para los valores numéricos:

Operador Resultado
x > y Mayor que
x >= y Mayor o igual que
x < y Menor que
x <= y Menor o igual que
x = y Igual
x <> y No igual a
x + y Suma
x - y Resta
x * y Producto
x / y Cociente
x ?? y Coalesce
+x Suma unaria
-x Negación

El tipo nativo de los valores numéricos es el tipo intrínseco number.

Hora

Un valor de hora almacena una representación opaca de la hora del día. Una hora se codifica como el número de tics desde la medianoche, que cuenta el número de tics de 100 nanosegundos que han transcurrido en un reloj de 24 horas. El número máximo de tics desde la medianoche se corresponde a las 23:59:59,9999999.

Aunque no hay ninguna sintaxis literal para las horas, se proporcionan varias funciones estándar de biblioteca para construirlas. Las horas también pueden construirse mediante la función intrínseca #time:

#time(hour, minute, second)

Debe suceder lo siguiente o se generará un error con el código de motivo Expression.Error:

0 ≤ hora ≤ 24
0 ≤ minuto ≤ 59
0 ≤ segundo ≤ 59

Además, si hora = 24, el minuto y el segundo deben ser cero.

Los operadores siguientes se definen para los valores de hora:

Operador Resultado
x = y Igual
x <> y No igual a
x >= y Mayor o igual que
x > y Mayor que
x < y Menor que
x <= y Menor o igual que
x ?? y Coalesce

Los operadores siguientes permiten que uno o los dos operandos sean una fecha:

Operador Operando izquierdo Operando derecho Significado
x + y time duration Desplazamiento de fecha según la duración
x + y duration time Desplazamiento de fecha según la duración
x - y time duration Desplazamiento de fecha según la duración negada
x - y time time Duración entre fechas
x & y date time Fecha y hora combinadas

El tipo nativo de los valores de hora es el tipo intrínseco time.

Fecha

Un valor de fecha almacena una representación opaca de un día concreto. Una fecha se codifica como un número de días desde la época, a partir del 1 de enero del año 1 E. C. en el calendario gregoriano. El número máximo de días transcurridos desde la época es 3 652 058, que se corresponde al 31 de diciembre de 9999.

Aunque no hay ninguna sintaxis literal para las fechas, se proporcionan varias funciones estándar de biblioteca para construirlas. Las fechas también pueden construirse mediante la función intrínseca #date:

#date(year, month, day)

Debe suceder lo siguiente o se generará un error con el código de motivo Expression.Error:

1 ≤ año ≤ 9999
1 ≤ mes ≤ 12
1 ≤ día ≤ 31

Además, el día debe ser válido para el mes y año elegidos.

Los operadores siguientes se definen para los valores de fecha:

Operador Resultado
x = y Igual
x <> y No igual a
x >= y Mayor o igual que
x > y Mayor que
x < y Menor que
x <= y Menor o igual que
x ?? y Coalesce

Los operadores siguientes permiten que uno o los dos operandos sean una fecha:

Operador Operando izquierdo Operando derecho Significado
x + y date duration Desplazamiento de fecha según la duración
x + y duration date Desplazamiento de fecha según la duración
x - y date duration Desplazamiento de fecha según la duración negada
x - y date date Duración entre fechas
x & y date time Fecha y hora combinadas

El tipo nativo de los valores de fecha es el tipo intrínseco date.

DateTime

Un valor de fecha y hora contiene una fecha y una hora.

Aunque no hay ninguna sintaxis literal para los valores de fecha y hora, se proporcionan varias funciones estándar de biblioteca para construirlos. Los valores de fecha y hora también pueden construirse mediante la función intrínseca #datetime:

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

Debe suceder lo siguiente o se generará un error con el código de motivo Expression.Error: 1 ≤ año ≤ 9999
1 ≤ mes ≤ 12
1 ≤ día ≤ 31
0 ≤ hora ≤ 23
0 ≤ minuto ≤ 59
0 ≤ segundo ≤ 59

Además, el día debe ser válido para el mes y año elegidos.

Los operadores siguientes se definen para los valores de fecha y hora:

Operador Resultado
x = y Igual
x <> y No igual a
x >= y Mayor o igual que
x > y Mayor que
x < y Menor que
x <= y Menor o igual que
x ?? y Coalesce

Los operadores siguientes permiten que uno o los dos operandos sean un valor de fecha y hora:

Operador Operando izquierdo Operando derecho Significado
x + y datetime duration Desplazamiento de fecha y hora según la duración
x + y duration datetime Desplazamiento de fecha y hora según la duración
x - y datetime duration Desplazamiento de fecha y hora según la duración negada
x - y datetime datetime Duración entre fechas y horas

El tipo nativo de los valores de fecha y hora es el tipo intrínseco datetime.

Fecha, hora y zona horaria

Un valor de fecha, hora y zona horaria contiene una fecha, una hora y una zona horaria. Un valor zona horaria se codifica como un número de desplazamiento de minutos con respecto a la hora UTC, que cuenta el número de minutos que la parte de hora del valor datetime se debe desplazar con respecto a la hora universal coordinada (UTC). El número mínimo de desplazamiento de minutos con respecto a la hora UTC es -840, que representa un desplazamiento con respecto a la hora UTC de -14:00 o 14 horas antes que la hora UTC. El número máximo de desplazamiento de minutos con respecto a la hora UTC es 840, que corresponde a un desplazamiento con respecto a la hora UTC de 14:00.

Aunque no hay ninguna sintaxis literal para los valores de fecha, hora y zona horaria, se proporcionan varias funciones estándar de biblioteca para construirlos. Los valores de fecha, hora y zona horaria también pueden construirse mediante la función intrínseca #datetimezone:

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

Debe suceder lo siguiente o se generará un error con el código de motivo Expression.Error:

1 ≤ año ≤ 9999
1 ≤ mes ≤ 12
1 ≤ día ≤ 31
0 ≤ hora ≤ 23
0 ≤ minuto ≤ 59
0 ≤ segundo ≤ 59
-14 ≤ offset-hours ≤ 14
-59 ≤ offset-minutes ≤ 59

Además, el día debe ser válido para el mes y año elegidos y, si offset-hours = 14, entonces offset-minutes <= 0 y, si offset-hours = -14, entonces offset-minutes >= 0.

Los operadores siguientes se definen para los valores de fecha, hora y zona horaria:

Operador Resultado
x = y Igual
x <> y No igual a
x >= y Mayor o igual que
x > y Mayor que
x < y Menor que
x <= y Menor o igual que
x ?? y Coalesce

Los operadores siguientes permiten que uno o los dos operandos sean un valor de fecha, hora y zona horaria:

Operador Operando izquierdo Operando derecho Significado
x + y datetimezone duration Desplazamiento de zona horaria de fecha según la duración
x + y duration datetimezone Desplazamiento de zona horaria de fecha según la duración
x - y datetimezone duration Desplazamiento de zona horaria de fecha según la duración negada
x - y datetimezone datetimezone Duración entre zonas horarias de fecha

El tipo nativo de los valores de fecha, hora y zona horaria es el tipo intrínseco datetimezone.

Duración

Un valor de duración almacena una representación opaca de la distancia entre dos puntos en una escala de tiempo, medidos en tics de 100 segundos. La magnitud de una duración puede ser positiva o negativa; los valores positivos indican el progreso hacia delante en el tiempo y los negativos el progreso hacia atrás. El valor mínimo que se puede almacenar en una duración es -9 223 372 036 854 775 808 tics, o 10 675 199 días, 2 horas, 48 minutos y 05,4775808 segundos hacia atrás en el tiempo. El valor máximo que se puede almacenar en una duración es 9 223 372 036 854 775 807 tics, o 10 675 199 días, 2 horas, 48 minutos y 05,4775807 segundos hacia delante en el tiempo.

Aunque no hay ninguna sintaxis literal para las duraciones, se proporcionan varias funciones estándar de biblioteca para construirlos. Las duraciones también pueden construirse mediante la función intrínseca #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

Los operadores siguientes se definen para los valores de duración:

Operador Resultado
x = y Igual
x <> y No igual a
x >= y Mayor o igual que
x > y Mayor que
x < y Menor que
x <= y Menor o igual que
x ?? y Coalesce

Además, los operadores siguientes permiten que uno o los dos operandos sean un valor de duración:

Operador Operando izquierdo Operando derecho Significado
x + y datetime duration Desplazamiento de fecha y hora según la duración
x + y duration datetime Desplazamiento de fecha y hora según la duración
x + y duration duration Suma de las duraciones
x - y datetime duration Desplazamiento de fecha y hora según la duración negada
x - y datetime datetime Duración entre fechas y horas
x - y duration duration Resta de las duraciones
x * y duration number N veces una duración
x * y number duration N veces una duración
x / y duration number Fracción de una duración

El tipo nativo de los valores de duración es el tipo intrínseco duration.

Texto

Un valor de texto representa una secuencia de caracteres Unicode. Los valores de texto tienen una forma literal compatible con la gramática siguiente:

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

      Cualquier carácter excepto " (U+0022) o # (U+0023) seguido de ( (U+0028)
double-quote-escape-sequence:
      "" (U+0022, U+0022)

A continuación se muestra un ejemplo de un valor de texto:

"ABC" // the text value ABC

Los operadores siguientes se definen para los valores de texto:

Operador Resultado
x = y Igual
x <> y No igual a
x >= y Mayor o igual que
x > y Mayor que
x < y Menor que
x <= y Menor o igual que
x & y Concatenación
x ?? y Coalesce

El tipo nativo de los valores de texto es el tipo intrínseco text.

Binario

Un valor binario representa una secuencia de bytes.

Aunque no hay ninguna sintaxis literal para los valores binarios, se proporcionan varias funciones estándar de biblioteca para construirlos. Los valores binarios también pueden construirse mediante la función intrínseca #binary.

En el ejemplo siguiente se construye un valor binario a partir de una lista de bytes:

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

Los operadores siguientes se definen para los valores binarios:

Operador Resultado
x = y Igual
x <> y No igual a
x >= y Mayor o igual que
x > y Mayor que
x < y Menor que
x <= y Menor o igual que
x ?? y Coalesce

El tipo nativo de los valores binarios es el tipo intrínseco binary.

Lista

Un valor de lista es un valor que genera una secuencia de valores cuando se enumera. Un valor generado por una lista puede contener cualquier tipo de valor, incluida una lista. Las listas se pueden construir mediante la sintaxis de inicialización, como se indica a continuación:

list-expression:
      { item-listopt }
item-list:
      item
      item
,item-list
item:
      expresión
      expression
..expression

En el ejemplo siguiente de list-expression se define una lista con tres valores de texto: "A", "B" y "C".

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

El valor "A" es el primer elemento de la lista y el valor "C" es el último.

  • Los elementos de una lista no se evalúan hasta que se accede a ellos.
  • Aunque los valores de lista construidos con la sintaxis de lista producirán elementos en el orden en que aparecen en item-list, en general, las listas devueltas por las funciones de biblioteca pueden generar otro conjunto u otro número de valores cada vez que se enumeran.

Para incluir una secuencia de números enteros en una lista, se puede usar el formato a..b:

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

El número de elementos de una lista, conocido como recuento de lista, se puede determinar mediante la función List.Count.

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

Una lista puede tener un número infinito de elementos; para estas listas, no se define List.Count y puede producir un error o no finalizar.

Si una lista no contiene ningún elemento, se denomina lista vacía. Una lista vacía se escribe de esta forma:

{}  // empty list

Los operadores siguientes se definen para las listas:

Operador Resultado
x = y Igual
x <> y No igual a
x & y Concatenate
x ?? y Coalesce

Por ejemplo:

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

El tipo nativo de los valores de lista es el tipo intrínseco list, que especifica un tipo de elemento de any.

Registro

Un valor de registro es una secuencia ordenada de campos. Un campo está formado por un nombre de campo, que es un valor de texto que identifica de forma única el campo dentro del registro, y por un valor de campo. El valor de campo puede ser de cualquier tipo, incluido de registro. Los registros se pueden construir mediante la sintaxis de inicialización, como se indica a continuación:

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

En el ejemplo siguiente se crea un registro con un campo denominado x con el valor 1 y un campo denominado y con el valor 2.

[ x = 1, y = 2 ]

En el ejemplo siguiente se crea un registro con un campo denominado a con un valor de registro anidado. El registro anidado tiene un campo denominado b con el valor 2.

[ a = [ b = 2 ] ]

Cuando se evalúa una expresión de registro, sucede lo siguiente:

  • Se usa la expresión asignada a cada nombre de campo para determinar el valor del campo asociado.

  • Si la expresión asignada a un nombre de campo genera un valor cuando se evalúa, se convierte en el valor del campo del registro resultante.

  • Si la expresión asignada a un nombre de campo genera un error cuando se evalúa, el hecho de que se haya producido un error se registra con el campo junto con el valor de error que se haya producido. El acceso posterior a ese campo hará que se vuelva a generar un error con el valor de error registrado.

  • La expresión se evalúa en un entorno como el primario solo con las variables combinadas que se corresponden con el valor de todos los campos del registro, excepto el que se inicializa.

  • Un valor de un registro no se evalúa hasta que se accede al campo correspondiente.

  • Un valor de un registro se evalúa como máximo una vez.

  • El resultado de la expresión es un valor de registro con un registro de metadatos vacío.

  • El orden de los campos dentro del registro se define mediante el orden en que aparecen en record-initializer-expression.

  • Cada nombre de campo que se especifica debe ser único dentro del registro o es un error. Los nombres se comparan mediante una comparación ordinal.

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

Un registro sin campos se denomina registro vacío y se escribe de esta manera:

[] // empty record

Aunque el orden de los campos de un registro no es significativo al acceder a un campo o comparar dos registros, es significativo en otros contextos, como cuando se enumeran los campos de un registro.

Los dos mismos registros producen resultados diferentes cuando se obtienen los campos:

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

El número de campos de un registro se puede determinar mediante la función Record.FieldCount. Por ejemplo:

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

Además de usar la sintaxis de inicialización de registros [ ], se pueden construir registros a partir de una lista de valores y una lista de nombres de campo o un tipo de registro. Por ejemplo:

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

Lo anterior equivale a:

[ a = 1, b = 2 ]

Los operadores siguientes se definen para los valores de registro:

Operador Resultado
x = y Igual
x <> y No igual a
x & y Combinar
x ?? y Coalesce

En los ejemplos siguientes se ilustran los operadores anteriores. Tenga en cuenta que la combinación de registros usa los campos del operando derecho para invalidar los campos del operando izquierdo, en caso de que haya una superposición de los nombres de campo.

[ 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

El tipo nativo de los valores de registro es el tipo intrínseco record, que especifica una lista vacía abierta de campos.

Tabla

Un valor de tabla es una secuencia ordenada de filas. Una fila es una secuencia ordenada de valores de columna. El tipo de la tabla determina la longitud de todas las filas de la tabla, los nombres y los tipos de las columnas de la tabla, y la estructura de las claves de la tabla (si existen).

Aunque no hay ninguna sintaxis literal para las tablas, se proporcionan varias funciones estándar de biblioteca para construirlas. Las tablas también pueden construirse mediante la función intrínseca #table.

En el ejemplo siguiente se construye una tabla a partir de una lista de nombres de columna y una lista de filas. La tabla resultante contendrá dos columnas de type any y tres filas.

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

#table también se puede usar para especificar un tipo de tabla completo:

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

Aquí, el nuevo valor de tabla tiene un tipo de tabla que especifica los nombres y los tipos de columna.

Los operadores siguientes se definen para los valores de tabla:

Operador Resultado
x = y Igual
x <> y No igual a
x & y Concatenación
x ?? y Coalesce

La concatenación de tablas alinea las columnas con el mismo nombre y rellena null para las columnas que solo aparecen en una de las tablas de operandos. En el ejemplo siguiente se muestra la concatenación de tablas:

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

El tipo nativo de los valores de tabla es un tipo de tabla personalizado (derivado del tipo intrínseco table) que enumera los nombres de columna, especifica todos los tipos de columna como any y no tiene claves. (Vaya a Tipos de tabla para obtener más información sobre los tipos de tabla).

Función

Un valor de función es un valor que asigna un conjunto de argumentos a un valor único. Los detalles de los valores de función se describen en Funciones.

Tipo

Un valor de tipo es un valor que clasifica otros valores. Los detalles de los valores de tipo se describen en Tipos.