Del via


Grundlæggende begreber

I dette afsnit beskrives de grundlæggende begreber, der vises i de efterfølgende afsnit.

Værdier

En enkelt datadel kaldes en værdi. Generelt er der to generelle kategorier af værdier: primitive værdier, som er atomiske og strukturerede værdier, som er konstrueret ud af primitive værdier og andre strukturerede værdier. Værdierne kan f.eks.

1 
true
3.14159 
"abc"

er primitive, fordi de ikke består af andre værdier. På den anden side er værdierne

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

konstrueres ved hjælp af primitive værdier og, hvis der er tale om posten, andre strukturerede værdier.

Udtryk

Et udtryk er en formel, der bruges til at konstruere værdier. Et udtryk kan dannes ved hjælp af en række syntaktiske konstruktioner. Følgende er nogle eksempler på udtryk. Hver linje er et separat udtryk.

"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"

Den nemmeste form for udtryk, som vist ovenfor, er en konstant, der repræsenterer en værdi.

Mere komplekse udtryk er bygget ud fra andre udtryk, kaldet underudtryk. Eksempler:

1 + 2

Ovenstående udtryk består faktisk af tre udtryk. Konstanterne 1 og 2 er underudtryk af det overordnede udtryk 1 + 2.

Udførelse af den algoritme, der er defineret af de syntaktiske konstruktioner, der bruges i et udtryk, kaldes evaluering af udtrykket. Hver type udtryk har regler for, hvordan det evalueres. Et konstantudtryk som f.eks 1 . opretter en konstant værdi, mens udtrykket a + b tager de resulterende værdier, der oprettes ved at evaluere to andre udtryk (a og b), og tilføjer dem sammen i henhold til nogle sæt regler.

Miljøer og variabler

Udtryk evalueres i et givet miljø. Et miljø er et sæt navngivne værdier, der kaldes variabler. Hver variabel i et miljø har et entydigt navn i miljøet kaldet et id.

Et udtryk på øverste niveau (eller rod) evalueres i det globale miljø. Det globale miljø leveres af udtryks evaluatoren i stedet for at blive bestemt ud fra indholdet af det udtryk, der evalueres. Indholdet af det globale miljø indeholder standardbiblioteksdefinitionerne og kan påvirkes af eksporter fra sektioner fra nogle sæt dokumenter. (For nemheds skyld antager eksemplerne i dette afsnit et tomt globalt miljø. Det betyder, at det antages, at der ikke er noget standardbibliotek, og at der ikke er andre sektionsbaserede definitioner.)

Det miljø, der bruges til at evaluere et underudtryk, bestemmes af det overordnede udtryk. De fleste typer overordnede udtryk evaluerer et underudtryk i det samme miljø, som de blev evalueret i, men nogle bruger et andet miljø. Det globale miljø er det overordnede miljø , hvor det globale udtryk evalueres.

Postinitialiseringsudtrykket evaluerer f.eks. underudtrykket for hvert felt med et ændret miljø. Det ændrede miljø indeholder en variabel for hvert af felterne i posten, bortset fra det, der initialiseres. Hvis du medtager de andre felter i posten, kan felterne afhænge af værdierne i felterne. Eksempler:

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

På samme måde evaluerer let-expression underudtrykket for hver variabel med et miljø, der indeholder hver af variablerne for let med undtagelse af det, der initialiseres. Let-expression evaluerer udtrykket efter in med et miljø, der indeholder alle variablerne:

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

(Det viser sig, at både record-initializer-expression og let-expression faktisk definerer to miljøer, hvoraf det ene omfatter den variabel, der initialiseres. Dette er nyttigt i forbindelse med avancerede rekursive definitioner og dækkes i identifikatorreferencer .

Hvis du vil oprette miljøer for underudtryk, "flettes" de nye variabler med variablerne i det overordnede miljø. I følgende eksempel vises miljøer for indlejrede poster:

[
    a = 
    [ 

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

I følgende eksempel vises miljøer for en post, der er indlejret i en 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

Fletning af variabler med et miljø kan medføre en konflikt mellem variabler (da hver variabel i et miljø skal have et entydigt navn). Konflikten løses på følgende måde: Hvis navnet på en ny variabel, der flettes, er det samme som en eksisterende variabel i det overordnede miljø, har den nye variabel forrang i det nye miljø. I følgende eksempel har den indre variabel (dybere indlejret) x forrang frem for den ydre variabel 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
]  

Identifikatorreferencer

En id-reference bruges til at referere til en variabel i et miljø.

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

Den nemmeste form for identifikatorreference er en exclusive-identifier-reference:

exclusive-identifier-reference:
      identifikator

Det er en fejl, at en exclusive-identifier-reference refererer til en variabel, der ikke er en del af miljøet i det udtryk, som identifikatoren vises i.

Det er en fejl for en exclusive-identifier-reference at referere til en identifikator, der i øjeblikket initialiseres, hvis den refererede identifikator er defineret i et record-initializer-expression eller let-expression. I stedet kan en inclusive-identifier-reference bruges til at få adgang til det miljø, der omfatter den identifikator, der initialiseres. Hvis der bruges en inclusive-identifier-reference i en anden situation, svarer den til en exclusive-identifier-reference.

inclusive-identifier-reference:
      @ identifikator

Dette er nyttigt, når du definerer rekursive funktioner, da navnet på funktionen normalt ikke ville være i området.

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

    x = Factorial(5) 
]

Som med et record-initializer-expression kan en inclusive-identifier-reference bruges i et let-expression til at få adgang til det miljø, der indeholder det id, der initialiseres.

Evalueringsrækkefølge

Overvej følgende udtryk, der initialiserer en post:

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

Når dette udtryk evalueres, opretter det følgende postværdi:

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

Udtrykket angiver, at værdierne for både felt og felt B skal være kendt for at udføre A + B beregningen for feltet C.A Dette er et eksempel på en afhængighedsrækkefølge af beregninger, der leveres af et udtryk. M-evaluatoren overholder afhængighedsrækkefølgen, der leveres af udtryk, men det er gratis at udføre de resterende beregninger i den rækkefølge, den vælger. Beregningsrækkefølgen kan f.eks. være:

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

Eller det kan være:

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

Eller da A og B ikke afhænger af hinanden, kan de beregnes samtidigt:

    B = 2 + 2 samtidig med A = 1 + 1
    C = A + B

Bivirkninger

Det er en enkel og effektiv beregningsmodel at tillade en udtryks evaluator automatisk at beregne beregningsrækkefølgen for de tilfælde, hvor der ikke er nogen eksplicitte afhængigheder angivet af udtrykket.

Den er dog afhængig af at kunne omarrangere beregninger. Da udtryk kan kalde funktioner, og disse funktioner kan overvåge tilstanden uden for udtrykket ved at udstede eksterne forespørgsler, er det muligt at konstruere et scenarie, hvor beregningsrækkefølgen betyder noget, men ikke registreres i udtrykkets delvise rækkefølge. En funktion kan f.eks. læse indholdet af en fil. Hvis denne funktion kaldes gentagne gange, kan eksterne ændringer af filen overholdes, og derfor kan omarrangering medføre observerede forskelle i programfunktionsmåden. Afhængigt af sådanne observerede evalueringsrækkefølger for korrektheden af et M-udtryk medfører det en afhængighed af bestemte implementeringsvalg, der kan variere fra den ene evaluator til den næste eller endda variere for den samme evaluator under forskellige omstændigheder.

Uforanderlighed

Når en værdi er beregnet, er den uforanderlig, hvilket betyder, at den ikke længere kan ændres. Dette forenkler modellen til evaluering af et udtryk og gør det nemmere at ræsonnere resultatet, da det ikke er muligt at ændre en værdi, når den er blevet brugt til at evaluere en efterfølgende del af udtrykket. Et postfelt beregnes f.eks. kun, når det er nødvendigt. Når den er beregnet, forbliver den dog fast for postens levetid. Selvom forsøget på at beregne feltet udløste en fejl, udløses den samme fejl igen ved hvert forsøg på at få adgang til det pågældende postfelt.

En vigtig undtagelse til den uforanderlige én gang beregnede regel gælder for liste-, tabel- og binære værdier, som har streaming-semantik. Streaming semantik gør det muligt for M at transformere datasæt, der ikke passer til hukommelsen på én gang. Med streaming oprettes de værdier, der returneres, når en given tabel, liste eller binær værdi optæles efter behov, hver gang der anmodes om dem. Da de udtryk, der definerer de optalte værdier, evalueres, hver gang de optæles, kan det output, de producerer, være forskelligt på tværs af flere optællinger. Det betyder ikke, at flere optællinger altid resulterer i forskellige værdier, bare at de kan være forskellige, hvis den datakilde eller M-logik, der bruges, er ikke-deterministisk.

Bemærk også, at funktionsprogrammet ikke er det samme som værdikonstruktion. Biblioteksfunktioner kan vise ekstern tilstand (f.eks. det aktuelle klokkeslæt eller resultaterne af en forespørgsel i forhold til en database, der udvikler sig over tid), hvilket gør dem ikke-deterministiske. Selvom funktioner, der er defineret i M, ikke som sådan viser en sådan ikke-deterministisk funktionsmåde, kan de, hvis de er defineret til at aktivere andre funktioner, der ikke er deterministiske.

En endelig kilde til ikke-determinisme i M er fejl. Fejl stopper evalueringer, når de opstår (op til det niveau, hvor de håndteres af et try-udtryk). Det er normalt ikke observeret, om a + b forårsaget evalueringen af a før b eller b før a (ignorere samtidighed her for nemheds skyld). Men hvis det underudtryk, der blev evalueret, først udløser en fejl, kan det bestemmes, hvilket af de to udtryk der blev evalueret først.