Основные понятия

В этом разделе рассматриваются основные понятия, которые отображаются в последующих разделах.

Values

Один фрагмент данных называется значением. В целом существует две общие категории значений: примитивные значения, которые являются атомарными и структурированными значениями, которые создаются из примитивных значений и других структурированных значений. Например, значения

1 
true
3.14159 
"abc"

являются примитивными в том, что они не состоят из других значений. С другой стороны, значения

{1, 2, 3} 
[ A = {1}, B = {2}, C = {3} ]

создаются с помощью примитивных значений и, в случае записи, других структурированных значений.

Выражения

Выражение — это формула, используемая для создания значений. Выражение может быть сформировано с помощью различных синтактических конструкций. Ниже приведены некоторые примеры выражений. Каждая строка — это отдельное выражение.

"Hello World"             // a text value 
123                       // a number 
1 + 2                     // sum of two numbers 
{1, 2, 3}                 // a list of three numbers 
[ x = 1, y = 2 + 3 ]      // a record containing two fields: 
                          //        x and y 
(x, y) => x + y           // a function that computes a sum 
if 2 > 1 then 2 else 1    // a conditional expression 
let x = 1 + 1  in x * 2   // a let expression 
error "A"                 // error with message "A"

Простейшая форма выражения, как показано выше, представляет собой литерал, представляющий значение.

Более сложные выражения создаются из других выражений, называемых вложенными выражениями. Например:

1 + 2

Приведенное выше выражение на самом деле состоит из трех выражений. 2 И 1 литералы являются вложенными выражениями родительского выражения1 + 2.

Выполнение алгоритма, определенного синтаксическими конструкциями, используемыми в выражении, называется вычислением выражения. Каждое выражение имеет правила для оценки. Например, литеральное выражение, например, создает константное значение, в то время как 1 выражение a + b принимает полученные значения, полученные путем оценки двух других выражений (a и b) и добавляя их вместе в соответствии с некоторыми набором правил.

Среды и переменные

Выражения оцениваются в заданной среде. Среда — это набор именованных значений, называемых переменными. Каждая переменная в среде имеет уникальное имя в среде с именем идентификатора.

Выражение верхнего уровня (или корневого) вычисляется в глобальной среде. Глобальная среда предоставляется вычислителем выражений, а не определяется из содержимого вычисляемого выражения. Содержимое глобальной среды включает стандартные определения библиотеки и может влиять на экспорт из разделов из некоторых наборов документов. (Для простоты примеры в этом разделе подразумевают пустую глобальную среду. То есть предполагается, что стандартная библиотека отсутствует и не существует других определений на основе разделов.)

Среда, используемая для вычисления вложенного выражения, определяется родительским выражением. Большинство типов родительских выражений вычисляют под-выражение в той же среде, в которой они были оценены, но некоторые из них будут использовать другую среду. Глобальная среда — это родительская среда , в которой вычисляется глобальное выражение.

Например, выражение record-initializer-вычисляет под-выражение для каждого поля с измененной средой. Измененная среда включает переменную для каждого поля записи, за исключением инициализированной. Включение других полей записи позволяет полям зависеть от значений полей. Например:

[  
    x = 1,          // environment: y, z 
    y = 2,          // environment: x, z 
    z = x + y       // environment: x, y
] 

Аналогичным образом, выражение let-expression вычисляет под-выражение для каждой переменной с средой, содержащей каждую из переменных пусть, кроме инициализированной. Выражение let-expression вычисляет выражение, следующее в среде, содержащей все переменные:

let 

    x = 1,          // environment: y, z 
    y = 2,          // environment: x, z 
    z = x + y       // environment: x, y
in
    x + y + z       // environment: x, y, z

(Оказывается, что оба инициализатора записи и let-expression фактически определяют две среды, одна из которых включает инициализированную переменную. Это полезно для расширенных рекурсивных определений и рассматривается в справочниках по идентификаторам .

Чтобы сформировать среды для вложенных выражений, новые переменные "объединяются" с переменными в родительской среде. В следующем примере показаны среды для вложенных записей:

[
    a = 
    [ 

        x = 1,      // environment: b, y, z 
        y = 2,      // environment: b, x, z 
        z = x + y   // environment: b, x, y 
    ], 
    b = 3           // environment: a
]  

В следующем примере показаны среды для записи, вложенной в let:

Let
    a =
    [
        x = 1,       // environment: b, y, z 
        y = 2,       // environment: b, x, z 
        z = x + y    // environment: b, x, y 
    ], 
    b = 3            // environment: a 
in 
    a[z] + b         // environment: a, b

Объединение переменных с средой может привести к конфликту между переменными (так как каждая переменная в среде должна иметь уникальное имя). Конфликт разрешается следующим образом: если имя новой переменной, объединяемой, совпадает с существующей переменной в родительской среде, новая переменная будет иметь приоритет в новой среде. В следующем примере внутренняя переменная x (более глубоко вложенная) будет иметь приоритет над внешней переменной x.

[
    a =
    [ 
        x = 1,       // environment: b, x (outer), y, z 
        y = 2,       // environment: b, x (inner), z 
        z = x + y    // environment: b, x (inner), y 
    ], 
    b = 3,           // environment: a, x (outer) 
    x = 4            // environment: a, b
]  

Ссылки на идентификаторы

Ссылка на идентификатор используется для ссылки на переменную в среде.

выражение-идентификатора:
      ссылка-на-идентификатор
ссылка-на-идентификатор:
      эксклюзивная-ссылка-на-идентификатор
      инклюзивный идентификатор-справочник

Простейшая форма ссылки на идентификатор является ссылкой на монопольный идентификатор:

эксклюзивная-ссылка-на-идентификатор:
      идентификатор

Ошибкой является то, когда эксклюзивная-ссылка-на-идентификатор ссылается на переменную, которая не является частью среды выражения, в которой отображается идентификатор.

Ошибкой является то, когда эксклюзивная-ссылка-на-идентификатор ссылается на идентификатор, который в текущий момент инициализируется, если он определен внутри выражения-инициализатора-записи или выражения-let. Вместо этого доступ к среде, включающей инициализируемый идентификатор, можно получить с помощью инклюзивной-ссылки-на-идентификатор. Если инклюзивная-ссылка-на- идентификатор используется в любой другой ситуации, то она эквивалентна эксклюзивной-ссылке-на-идентификатор.

инклюзивный идентификатор-справочник:
      @идентификатор

Это полезно при определении рекурсивных функций, так как имя функции обычно не будет находиться в область.

[ 
    Factorial = (n) =>
        if n <= 1 then
            1
        else
            n * @Factorial(n - 1),  // @ is scoping operator

    x = Factorial(5) 
]

Как и в случае с выражением record-initializer-expression, для доступа к среде, включающей инициализированный идентификатор, можно использовать в выражении let-expression.

Порядок вычислений

Рассмотрим следующее выражение, которое инициализирует запись:

[ 
    C = A + B, 
    A = 1 + 1, 
    B = 2 + 2 
]

При вычислении это выражение создает следующее значение записи:

[ 
    C = 6, 
    A = 2, 
    B = 4 
]

Выражение указывает, что для выполнения A + B вычисления поля Cзначения A поля и поля B должны быть известны. Это пример порядка зависимостей вычислений, предоставляемых выражением. Средство оценки M соблюдает порядок зависимостей, предоставляемый выражениями, но может выполнять оставшиеся вычисления в любом порядке, который он выбирает. Например, порядок вычислений может быть следующим:

A = 1 + 1 
B = 2 + 2 
C = A + B

Или это может быть:

B = 2 + 2 
A = 1 + 1 
C = A + B

Или, так как A и B не зависят друг от друга, их можно вычислить одновременно:

    B = 2 + 2параллельно с A = 1 + 1
    C = A + B

Побочные эффекты

Разрешение вычислителя выражений для автоматического вычисления порядка вычислений в случаях, когда явные зависимости, указанные выражением, являются простой и мощной вычислительной моделью.

Однако он полагается на возможность переупорядочения вычислений. Так как выражения могут вызывать функции, и эти функции могут наблюдать за состоянием вне выражения путем выдачи внешних запросов, можно создать сценарий, в котором порядок вычисления имеет значение, но не фиксируется в частичном порядке выражения. Например, функция может считывать содержимое файла. Если эта функция вызывается неоднократно, внешние изменения в этом файле могут наблюдаться и, следовательно, переупорядочение может привести к заметным различиям в поведении программы. В зависимости от такого наблюдаемого порядка оценки для правильности выражения M зависит от конкретных вариантов реализации, которые могут отличаться от одного вычислителя до следующего или даже могут отличаться от одного и того же вычислителя в различных обстоятельствах.

Неизменяемость

После вычисления значения она неизменяема, то есть она больше не может быть изменена. Это упрощает модель для оценки выражения и упрощает причину результата, так как невозможно изменить значение после его использования для оценки последующей части выражения. Например, поле записи вычисляется только при необходимости. Однако после вычисления он остается фиксированным для времени существования записи. Даже если попытка вычислить поле вызвала ошибку, эта же ошибка будет возникать снова при каждой попытке получить доступ к полю записи.

Важное исключение для неизменяемого одночисленного правила применяется к спискам, таблицам и двоичным значениям, которые имеют семантику потоковой передачи. Семантика потоковой передачи позволяет M преобразовывать наборы данных, которые не помещаются в память одновременно. При потоковой передаче значения, возвращаемые при перечислении заданной таблицы, списка или двоичного значения, создаются по запросу при каждом запросе. Так как выражения, определяющие перечисленные значения, вычисляются при каждом перечислении, выходные данные, которые они создают, могут отличаться в нескольких перечислениях. Это не означает, что несколько перечислений всегда приводят к разным значениям, так же, что они могут отличаться, если используемый источник данных или логика M не детерминирована.

Кроме того, обратите внимание, что приложение-функция не совпадает со строительством значений. Функции библиотеки могут предоставлять внешнее состояние (например, текущее время или результаты запроса к базе данных, развивающейся с течением времени), отрисовку недетерминированной. Хотя функции, определенные в M, не будут предоставлять такое недетерминированное поведение, они могут, если они определены для вызова других функций, которые являются недетерминированными.

Окончательным источником недетерминизма в M являются ошибки. Ошибки останавливают оценки при их возникновении (до уровня, в котором они обрабатываются выражением try). Обычно это не наблюдаемо, a + b вызвано ли вычисление a до b или b до a (игнорируя параллелизм здесь для простоты). Тем не менее, если вычисляемое подтекстовое выражение сначала вызывает ошибку, то ее можно определить, какие из двух выражений были оценены сначала.