Grunnleggende konsepter
Denne delen tar for seg grunnleggende begreper som vises i de påfølgende inndelingene.
Verdier
En enkelt del av dataene kalles en verdi. Generelt sett er det to generelle kategorier av verdier: primitive verdier, som er atomiske og strukturerte verdier, som er konstruert av primitive verdier og andre strukturerte verdier. For eksempel verdiene
1
true
3.14159
"abc"
er primitive ved at de ikke består av andre verdier. På den annen side, verdiene
{1, 2, 3}
[ A = {1}, B = {2}, C = {3} ]
konstrueres ved hjelp av primitive verdier og, i tilfelle av posten, andre strukturerte verdier.
Uttrykk
Et uttrykk er en formel som brukes til å konstruere verdier. Et uttrykk kan dannes ved hjelp av en rekke syntaktiske konstruksjoner. Nedenfor finner du noen eksempler på uttrykk. Hver linje er et eget uttrykk.
"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 enkleste formen for uttrykk, som vist ovenfor, er en litteral som representerer en verdi.
Mer komplekse uttrykk er bygget fra andre uttrykk, kalt deluttrykk. Eksempel:
1 + 2
Uttrykket ovenfor består faktisk av tre uttrykk. 2
Og 1
litteraler er underuttrykk av det overordnede uttrykket1 + 2
.
Kjøring av algoritmen som er definert av de syntaktiske konstruksjonene som brukes i et uttrykk, kalles evaluering av uttrykket. Hver type uttrykk har regler for hvordan det evalueres. For eksempel vil et litteral uttrykk som 1
produsere en konstant verdi, mens uttrykket a + b
vil ta de resulterende verdiene som produseres ved å evaluere to andre uttrykk (a
og b
) og legge dem sammen i henhold til noen sett med regler.
Miljøer og variabler
Uttrykk evalueres i et gitt miljø. Et miljø er et sett med navngitte verdier, kalt variabler. Hver variabel i et miljø har et unikt navn i miljøet som kalles en identifikator.
Et uttrykk på øverste nivå (eller rot) evalueres i det globale miljøet. Det globale miljøet leveres av uttrykksevaluatoren i stedet for å bestemmes ut fra innholdet i uttrykket som evalueres. Innholdet i det globale miljøet omfatter standard bibliotekdefinisjoner og kan påvirkes av eksporter fra inndelinger fra enkelte dokumenter. (Eksemplene i denne delen forutsetter et tomt globalt miljø for enkelhetshet. Dette er, det antas at det ikke finnes noe standardbibliotek, og at det ikke finnes noen andre inndelingsbaserte definisjoner.)
Miljøet som brukes til å evaluere et underuttrykk, bestemmes av det overordnede uttrykket. De fleste overordnede uttrykkstyper evaluerer et deluttrykk i det samme miljøet de ble evaluert i, men noen vil bruke et annet miljø. Det globale miljøet er det overordnede miljøet der det globale uttrykket evalueres.
Postinitialiserer-uttrykket evaluerer for eksempel deluttrykket for hvert felt med et endret miljø. Det endrede miljøet inkluderer en variabel for hvert av feltene i posten, bortsett fra det som initialiseres. Hvis du inkluderer de andre feltene i posten, kan feltene avhenge av verdiene i feltene. Eksempel:
[
x = 1, // environment: y, z
y = 2, // environment: x, z
z = x + y // environment: x, y
]
På samme måte evaluerer let-uttrykket deluttrykket for hver variabel med et miljø som inneholder hver av variablene i la, bortsett fra den som initialiseres. La-uttrykket evaluerer uttrykket som følger med et miljø som inneholder alle variablene:
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 seg at både record-initializer-uttrykk og let-expression faktisk definerer to miljøer, hvorav den ene inkluderer variabelen som initialiseres. Dette er nyttig for avanserte rekursive definisjoner og dekkes i identifikatorreferanser .
Hvis du vil danne miljøene for deluttrykkene, slås de nye variablene sammen med variablene i det overordnede miljøet. Følgende eksempel viser miljøene for nestede 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
]
Følgende eksempel viser miljøene for en post nestet i en la:
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
Sammenslåing av variabler med et miljø kan føre til en konflikt mellom variabler (siden hver variabel i et miljø må ha et unikt navn). Konflikten løses som følger: Hvis navnet på en ny variabel som slås sammen, er det samme som en eksisterende variabel i det overordnede miljøet, vil den nye variabelen ha prioritet i det nye miljøet. I eksemplet nedenfor vil den indre (dypere nestede) variabelen x
ha prioritet over den ytre variabelen 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
]
Identifikatorreferanser
En identifikatorreferanse brukes til å referere til en variabel i et miljø.
identifikator-uttrykk:
identifikatorreferanse
identifikatorreferanse:
eksklusiv-identifikator-referanse
inclusive-identifier-reference
Den enkleste formen for identifikatorreferanse er en eksklusiv identifikatorreferanse:
eksklusiv-identifikator-referanse:
Identifikator
Det er en feil for en eksklusiv identifikatorreferanse å referere til en variabel som ikke er en del av miljøet i uttrykket som identifikatoren vises i.
Det er en feil for en eksklusiv-identifikator-referanse å referere til en identifikator som for øyeblikket initialiseres hvis den refererte identifikatoren er definert i et post-initializer-uttrykk eller let-uttrykk. I stedet kan en inkluderende identifikatorreferanse brukes til å få tilgang til miljøet som inkluderer identifikatoren som initialiseres. Hvis en inkluderende identifikatorreferanse brukes i en annen situasjon, tilsvarer den en eksklusiv identifikatorreferanse.
inclusive-identifier-reference:
@
Identifikator
Dette er nyttig når du definerer rekursive funksjoner siden navnet på funksjonen normalt ikke er i omfang.
[
Factorial = (n) =>
if n <= 1 then
1
else
n * @Factorial(n - 1), // @ is scoping operator
x = Factorial(5)
]
Som med et postinitialiserer-uttrykk, kan en inkluderende identifikatorreferanse brukes i et la-uttrykk for å få tilgang til miljøet som inkluderer identifikatoren som initialiseres.
Evalueringsrekkefølge
Vurder følgende uttrykk som initialiserer en post:
[
C = A + B,
A = 1 + 1,
B = 2 + 2
]
Når det evalueres, produserer dette uttrykket følgende postverdi:
[
C = 6,
A = 2,
B = 4
]
Uttrykket sier at for å kunne utføre beregningen A + B
for felt C
må verdiene for både felt A
og felt B
være kjent. Dette er et eksempel på en avhengighetsrekkefølge for beregninger som leveres av et uttrykk. M-evaluatoren overholder avhengighetsrekkefølgen som leveres av uttrykk, men står fritt til å utføre de gjenværende beregningene i hvilken som helst rekkefølge den velger. Beregningsrekkefølgen kan for eksempel 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 siden A
og B
ikke avhenger av hverandre, kan de beregnes samtidig:
B = 2 + 2
samtidig med A = 1 + 1
C = A + B
Bivirkninger
Å tillate at en uttrykksevaluator automatisk beregner beregningsrekkefølgen for tilfeller der det ikke er noen eksplisitte avhengigheter angitt av uttrykket, er en enkel og kraftig beregningsmodell.
Det er imidlertid avhengig av å kunne omorganisere beregninger. Siden uttrykk kan kalle opp funksjoner, og disse funksjonene kan observere tilstand eksternt for uttrykket ved å utstede eksterne spørringer, er det mulig å konstruere et scenario der beregningsrekkefølgen betyr noe, men ikke fanges opp i den delvise rekkefølgen av uttrykket. En funksjon kan for eksempel lese innholdet i en fil. Hvis denne funksjonen kalles gjentatte ganger, kan eksterne endringer i filen observeres, og derfor kan omorganisering føre til observerbare forskjeller i programvirkemåten. Avhengig av en slik observert evalueringsrekkefølge for riktigheten av et M-uttrykk forårsaker en avhengighet av bestemte implementeringsvalg som kan variere fra én evaluator til den neste, eller kan til og med variere på samme evaluator under ulike omstendigheter.
Uforanderlighet
Når en verdi er beregnet, er den uforanderlig, noe som betyr at den ikke lenger kan endres. Dette forenkler modellen for evaluering av et uttrykk og gjør det enklere å tenke på resultatet fordi det ikke er mulig å endre en verdi når den har blitt brukt til å evaluere en etterfølgende del av uttrykket. Et postfelt beregnes for eksempel bare ved behov. Men når den er beregnet, forblir den fast for postens levetid. Selv om forsøket på å beregne feltet oppstod en feil, vil den samme feilen bli utløst på nytt på hvert forsøk på å få tilgang til dette postfeltet.
Et viktig unntak fra den uforanderlige en gang beregnede regelen gjelder for liste-, tabell- og binærverdier, som har semantikk for strømming. Strømmantics tillater M å transformere datasett som ikke passer inn i minnet på en gang. Med strømming produseres verdiene som returneres når du nummererer en gitt tabell, liste eller binærverdi, ved behov hver gang de blir forespurt. Siden uttrykkene som definerer de opplistede verdiene evalueres hver gang de nummereres, kan utdataene de produserer være forskjellige på tvers av flere opplistinger. Dette betyr ikke at flere opplistinger alltid resulterer i forskjellige verdier, bare at de kan være forskjellige hvis datakilden eller M-logikken som brukes, ikke er deterministisk.
Vær også oppmerksom på at funksjonsprogrammet ikke er det samme som verdikonstruksjon. Bibliotekfunksjoner kan vise ekstern tilstand (for eksempel gjeldende klokkeslett eller resultatene av en spørring mot en database som utvikler seg over tid), noe som gjengir dem ikke-deterministiske. Selv om funksjoner definert i M ikke, som sådan, viser en slik ikke-deterministisk atferd, kan de hvis de er definert til å aktivere andre funksjoner som ikke er deterministiske.
En endelig kilde til ikke-determinisme i M er feil. Feil stopper evalueringer når de oppstår (opp til nivået der de håndteres av et prøveuttrykk). Det er normalt ikke observerbart om a + b
forårsaket evalueringen av a
før b
eller b
før a
(ignorerer samtidighet her for enkelhet). Hvis deluttrykket som ble evaluert først, oppstår en feil, kan det imidlertid fastslås hvilke av de to uttrykkene som ble evaluert først.