다음을 통해 공유


기본 개념

이 섹션에서는 후속 섹션 전체에 표시되는 기본 개념에 대해 설명합니다.

단일 데이터 조각을 값이라고 부릅니다. 대체로 두 가지 일반적인 값 범주인 원자성 값과 기본 값 및 기타 구조화된 값으로 구성된 구조화된 값이 있습니다. 예를 들어 값

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 식은 다른 두 식(ab)을 평가하여 생성된 결과 값을 가져와서 일부 규칙 집합에 따라 함께 추가합니다.

환경 및 변수

식은 지정된 환경 내에서 평가됩니다. 환경은 변수라는 명명된 값 집합입니다. 환경의 각 변수에는 식별자라는 환경 내의 고유한 이름이 있습니다.

최상위(또는 루트) 식은 전역 환경 내에서 평가됩니다. 전역 환경은 계산되는 식의 내용에서 결정되는 대신 식 계산기에서 제공됩니다. 전역 환경의 콘텐츠에는 표준 라이브러리 정의가 포함되며 일부 문서 집합의 섹션 내보내기의 영향을 받을 수 있습니다. (보다 간단하게 설명하자면, 이 섹션의 예제에서는 비어 있는 전역 환경을 가정합니다. 즉, 표준 라이브러리가 없고 다른 섹션 기반 정의도 없다고 가정하는 것입니다.)

하위 식을 평가하는 데 사용되는 환경은 부모 식에 의해 결정됩니다. 대부분의 부모 식 종류는 동일한 환경에서 평가된 하위 식을 평가하지만 일부는 다른 환경을 사용합니다. 전역 환경은 전역 식이 평가되는 부모 환경 입니다.

예를 들어 레코드 이니셜라이저 식수정된 환경이 있는 각 필드에 대한 하위 식을 평가합니다. 수정된 환경에는 초기화되는 필드를 제외하고 레코드의 각 필드에 대한 변수가 포함됩니다. 레코드의 다른 필드를 포함하면 필드의 값에 따라 필드가 달라질 수 있습니다. 예시:

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

마찬가지로 let 식초기화되는 변수를 제외한 let의 각 변수를 포함하는 환경을 사용하여 각 변수에 대한 하위 식을 평가합니다. let 식모든 변수가 포함된 환경을 사용하여 in 다음에 있는 식을 평가합니다.

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 식실제로 두 환경을 정의하며, 그 중 하나에는 초기화되는 변수가 포함됩니다. 고급 재귀 정의에 유용하며 식별자 참조에서 다룹니다 .

하위 식에 대한 환경을 형성하기 위해 새 변수는 부모 환경의 변수와 "병합"됩니다. 다음 예제에서는 중첩된 레코드에 대한 환경을 보여 줍니다.

[
    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

변수를 환경과 병합하면 변수 간에 충돌이 발생할 수 있습니다(환경의 각 변수에는 고유한 이름이 있어야 하므로). 충돌은 다음과 같이 해결됩니다. 병합되는 새 변수의 이름이 부모 환경의 기존 변수와 같으면 새 변수가 새 환경에서 우선적으로 적용됩니다. 다음 예제에서는 내부(더 깊이 중첩된) 변수가 외부 변수 xx보다 우선합니다.

[
    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
]  

식별자 참조

식별자 참조는 환경 내의 변수를 참조하는 데 사용됩니다.

identifier-expression:
      identifier-reference
identifier-reference:
      exclusive-identifier-reference
      inclusive-identifier-reference

식별자 참조의 가장 간단한 형식은 단독 식별자 참조입니다.

exclusive-identifier-reference:
      identifier

exclusive-identifier-reference가 식별자가 나타나는 식의 환경에 속하지 않는 변수를 참조하는 것은 오류입니다.

exclusive-identifier-reference가 현재 초기화되고 있는 식별자를 참조하는 것은 참조되는 식별자가 record-initializer-expression 또는 let-expression 내부에서 정의되고 있는 경우 오류입니다. 그 대신 inclusive-identifier-reference를 사용하여, 초기화되고 있는 식별자가 속한 환경에 대한 액세스 권한을 얻을 수 있습니다. inclusive-identifier-reference가 그 밖의 다른 상황에서 사용되는 경우에는 exclusive-identifier-reference와 동일합니다.

inclusive-identifier-reference:
      @identifier

이 기능은 함수 이름이 일반적으로 범위에 있지 않으므로 재귀 함수를 정의할 때 유용합니다.

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

    x = Factorial(5) 
]

레코드 이니셜라이저 식마찬가지로 let 식 내에서 포괄 식별자 참조 사용하여 초기화되는 식별자를 포함하는 환경에 액세스할 수 있습니다.

계산 순서

레코드를 초기화하는 다음 식을 고려합니다.

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

계산될 때 이 식은 다음 레코드 값을 생성합니다.

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

식은 필드에 대한 계산을 A + B 수행하려면 필드 C와 필드 AB 의 값을 모두 알고 있어야 한다고 명시합니다. 식에서 제공하는 계산의 종속성 순서 의 예입니다. M 계산기는 식에서 제공하는 종속성 순서를 준수하지만 선택한 순서에 따라 다시 기본 계산을 자유롭게 수행할 수 있습니다. 예를 들어 계산 순서는 다음과 같습니다.

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

또는 다음이 될 수 있습니다.

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

또는 서로 의존하지 않기 때문에 AB 동시에 계산할 수 있습니다.

    B = 2 + 2concurrently withA = 1 + 1
    C = A + B

파생 작업

식 계산기에서 명시적 종속성이 없는 경우 계산 순서를 자동으로 계산하도록 허용하는 것은 간단하고 강력한 계산 모델입니다.

그러나 계산 순서를 다시 정렬할 수 있어야 합니다. 식은 함수를 호출할 수 있고 이러한 함수는 외부 쿼리를 실행하여 식 외부의 상태를 관찰할 수 있으므로 계산 순서가 중요하지만 식의 부분 순서로 캡처되지 않는 시나리오를 생성할 수 있습니다. 예를 들어 함수는 파일의 내용을 읽을 수 있습니다. 해당 함수가 반복적으로 호출되는 경우 해당 파일에 대한 외부 변경 내용을 관찰할 수 있으므로 순서를 다시 지정하면 프로그램 동작에서 관찰 가능한 차이가 발생할 수 있습니다. 이러한 관찰된 평가 순서에 따라 M 식의 정확성에 따라 특정 구현 선택에 대한 종속성이 발생하며, 이는 하나의 평가자에서 다음 평가자에 따라 달라지거나 다양한 상황에서 동일한 평가자에 따라 달라질 수도 있습니다.

불변성

값이 계산 되면 변경할 수 없으므로 더 이상 변경할 수 없습니다. 이렇게 하면 식을 평가하기 위한 모델이 간소화되고 식의 후속 부분을 평가하는 데 사용된 값을 변경할 수 없으므로 결과에 대해 더 쉽게 추론할 수 있습니다. 예를 들어 레코드 필드는 필요한 경우에만 계산됩니다. 그러나 계산되면 레코드의 수명 동안 고정된 기본. 필드를 계산하려고 하면 오류가 발생하더라도 해당 레코드 필드에 액세스하려는 모든 시도에서 동일한 오류가 다시 발생합니다.

변경할 수 없는 한 번 계산된 규칙에 대한 중요한 예외는 스트리밍 의미 체계가 있는 목록, 테이블 및 이진 값에 적용됩니다. 스트리밍 의미 체계를 사용하면 M이 메모리에 한꺼번에 맞지 않는 데이터 집합을 변환할 수 있습니다. 스트리밍을 사용하면 요청될 때마다 지정된 테이블, 목록 또는 이진 값을 열거할 때 반환되는 값이 요청 시 생성됩니다. 열거된 값을 정의하는 식은 열거될 때마다 평가되므로 생성되는 출력은 여러 열거형에서 다를 수 있습니다. 이는 여러 열거형이 항상 다른 값을 생성한다는 것을 의미하지는 않으며, 사용되는 데이터 원본 또는 M 논리가 비결정적이면 서로 다를 수 있습니다.

또한 함수 애플리케이션은 값 생성과 동일하지 않습니다 . 라이브러리 함수는 외부 상태(예: 현재 시간 또는 시간이 지남에 따라 진화하는 데이터베이스에 대한 쿼리 결과)를 노출하여 비결정적으로 렌더링할 수 있습니다. M에 정의된 함수는 이러한 비결정적 동작을 노출하지 않지만 비결정적인 다른 함수를 호출하도록 정의된 경우 이러한 동작을 노출할 수 있습니다.

M에서 비결정주의의 최종 원인은 오류입니다. 오류가 발생하면 평가를 중지합니다(try 식에서 처리하는 수준까지). 일반적으로 이전 또는 b 이전 aab 평가를 발생했는지 여부를 a + b 관찰할 수 없습니다(단순성을 위해 여기에서 동시성을 무시). 그러나 평가된 하위 식이 먼저 오류를 발생시키는 경우 두 식 중 먼저 평가된 식을 확인할 수 있습니다.