Peruskäsitteet
Tässä osiossa käsitellään peruskäsitteitä, jotka näkyvät kaikissa seuraavissa osissa.
Arvot
Yksittäistä tieto-osaa kutsutaan arvoksi. Yleisesti ottaen on olemassa kaksi yleistä arvoluokkaa: primitiiviset arvot, jotka ovat atomisia, ja rakennearvot, jotka on valmistettu primitiivisistä arvoista ja muista rakennearvoista. Esimerkiksi arvot
1
true
3.14159
"abc"
ovat primitiivisiä siinä mielessä, että ne eivät ole muiden arvojen tekemiä. Toisaalta arvot
{1, 2, 3}
[ A = {1}, B = {2}, C = {3} ]
rakennetaan käyttäen primitiivisiä arvoja ja, jos kyseessä on tietue, muita jäsennettyjä arvoja.
Lausekkeet
Lauseke on kaava, jota käytetään arvojen muodostamiseen. Lauseke voidaan muodostaa käyttämällä erilaisia syntaktisia rakenteita. Seuraavissa on esimerkkejä lausekkeista. Jokainen rivi on erillinen lauseke.
"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"
Yksinkertaisin lausekemuoto, kuten yllä nähdään, on literaali, joka edustaa arvoa.
Monimutkaisemmat lausekkeet on muodostettu muista lausekkeista, joita kutsutaan alilausekkeiksi. Esimerkkejä:
1 + 2
Yllä oleva lauseke koostuu itse asiassa kolmesta lausekkeesta. Literaalit 1
ja 2
ovat päälausekkeen 1 + 2
alilausekkeita.
Lausekkeessa käytettyjen syntaktisten rakenteiden määrittämän algoritmin suorittamista kutsutaan lausekkeen arvioimiseksi . Jokaisella lausekkeella on sääntöjä siitä, miten sitä arvioidaan. Esimerkiksi literaalilauseke, kuten 1
, tuottaa vakioarvon, kun taas lauseke a + b
käyttää tulokseksi saatuja arvoja arvioimalla kahta muuta lauseketta (a
ja ) ja b
lisäämään ne yhteen joidenkin sääntöjen mukaisesti.
Ympäristöt ja muuttujat
Lausekkeet arvioidaan tietyssä ympäristössä. Ympäristö on joukko nimettyjä arvoja, joita kutsutaan muuttujiksi. Jokaisella ympäristön muuttujalla on yksilöivä nimi ympäristössä, jota kutsutaan tunnisteeksi.
Ylimmän tason (tai juuren) lauseke arvioidaan yleisessä ympäristössä. Lausekkeen arvioija tarjoaa yleisen ympäristön sen sijaan, että se määritettiin arvioitavan lausekkeen sisällöstä. Yleisen ympäristön sisältö sisältää kirjaston vakiomääritykset, ja se voi koskea joidenkin asiakirjojen osien tuontia. (Selvyyden vuoksi tämän osion esimerkit ovat yleisen ympäristön osalta tyhjiä. Oletetaan, että vakiokirjastoa ei ole ja että muita osapohjaisia määrityksiä ei ole olemassa.)
Alilausekkeen arvioimiseen käytettävä ympäristö määräytyy päälausekkeen mukaan. Useimmat päälausekelajit arvioivat alilauseketta samassa ympäristössä, jossa ne arvioitiin, mutta jotkin käyttävät eri ympäristöä. Yleinen ympäristö on pääympäristö , jossa yleinen lauseke arvioidaan.
Esimerkiksi record-initializer-lauseke arvioi alilausekkeen kullekin kentälle muokatussa ympäristössä. Muokattu ympäristö sisältää muuttujan kullekin tietueen kentälle, lukuun ottamatta sitä, jota valmistellaan. Tietueen muut kentät mukaan lukien mahdollistavat kenttien riippuvuus kenttien arvoista. Esimerkkejä:
[
x = 1, // environment: y, z
y = 2, // environment: x, z
z = x + y // environment: x, y
]
Samoin let-lauseke arvioi alilausekkeen kullekin muuttujalle, jossa on ympäristö, joka sisältää kaikki let-muuttujat paitsi niitä, joita valmistellaan. Let-lauseke arvioi lausekkeen sen jälkeen, kun ympäristö sisältää kaikki muuttujat:
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
(Näyttää siltä, että sekä record-initializer-lauseke että let-expression itse asiassa määrittävät kaksi ympäristöä, joista toinen sisältää alustetun muuttujan. Tästä on hyötyä tarkennetuissa rekursiivisissa määritelmissä, ja se käsitellään tunnisteviittauksissa .
Jos haluat muodostaa alilausekkeiden ympäristöt, uudet muuttujat yhdistetään pääympäristön muuttujiin. Seuraavassa esimerkissä näytetään sisäkkäisten tietueiden ympäristöt:
[
a =
[
x = 1, // environment: b, y, z
y = 2, // environment: b, x, z
z = x + y // environment: b, x, y
],
b = 3 // environment: a
]
Seuraavassa esimerkissä näytetään let-kentässä sisäkkäisen tietueen ympäristöt:
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
Muuttujien yhdistäminen ympäristöön voi aiheuttaa ristiriidan muuttujien välillä (koska jokaisella ympäristön muuttujalla on oltava yksilöivä nimi). Ristiriita ratkaistaan seuraavasti: jos yhdistettävän uuden muuttujan nimi on sama kuin olemassa oleva muuttuja pääympäristössä, uusi muuttuja on etusijalla uudessa ympäristössä. Seuraavassa esimerkissä sisempi (syvempi sisäkkäinen) muuttuja x
ohittaa ulomman muuttujan 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
]
Tunnisteviittaukset
Tunnisteviittausta käytetään viittaamaan muuttujaan ympäristössä.
identifier-expression:
tunnisteviittaus
identifier-reference:
exclusive-identifier-reference
inclusive-identifier-reference
Tunnisteviittauksen yksinkertaisin muoto on exclusive-identifier-reference:
exclusive-identifier-reference:
tunniste
Se on exclusive-identifier-reference -virhe jolla viitataan muuttujaan, joka ei ole osa lauseketta, jossa tunniste esiintyy.
Se on exclusive-identifier-reference -virhe jolla viitataan tunnisteeseen, jota valmistellaan parhaillaan, jos viitattu tunniste on määritetty record-initializer-lausekkeen tai let-expression-lausekkeen sisällä. Sen sijaan inclusive-identifier-reference -viitteellä voidaan käyttää ympäristöä, joka sisältää alustettavat tunnisteet. Jos inclusive-identifier-reference-viittausta käytetään missä tahansa muussa tilanteessa, se vastaa exclusive-identifier-reference-viittausta.
inclusive-identifier-reference:
@
tunniste
Tästä on hyötyä määritettäessä rekursiivisia funktioita, koska funktion nimi ei tavallisesti sisälly laajuuteen.
[
Factorial = (n) =>
if n <= 1 then
1
else
n * @Factorial(n - 1), // @ is scoping operator
x = Factorial(5)
]
Kuten record-initializer-lausekkeessa, inclusive-identifier-viittausta voidaan käyttää let-lausekkeessa, jotta voit käyttää ympäristöä, joka sisältää alustettavan tunnisteen.
Arviointijärjestys
Harkitse seuraavaa lauseketta, joka alustaa tietueen:
[
C = A + B,
A = 1 + 1,
B = 2 + 2
]
Kun tämä lauseke arvioidaan, se tuottaa seuraavan tietuearvon:
[
C = 6,
A = 2,
B = 4
]
Lauseke ilmaisee, että kentän laskennan suorittamiseksi A + B
on oltava tiedossa sekä kentän A
että kentän B
arvot.C
Tämä on esimerkki lausekkeen tarjoamista laskutoimitusten riippuvuusjärjestyksestä . M-arvioija noudattaa lausekkeiden tarjoamaa riippuvuusjärjestystä, mutta se voi suorittaa jäljellä olevat laskutoimitukset valitsemassaan järjestyksessä. Laskentajärjestys voi olla esimerkiksi seuraava:
A = 1 + 1
B = 2 + 2
C = A + B
Tai se voi olla:
B = 2 + 2
A = 1 + 1
C = A + B
Tai koska A
ja B
eivät riipu toisistaan, ne voidaan laskea samanaikaisesti:
B = 2 + 2
ja samaan aikaan kuin A = 1 + 1
C = A + B
Haittavaikutuksia
Lausekkeen arvioijan sallitaan automaattisesti laskea laskutoimitusten järjestys tapauksissa, joissa lausekkeessa ei ole eksplisiittisiä riippuvuuksia, on yksinkertainen ja tehokas laskentamalli.
Se kuitenkin luottaa siihen, että laskennan voi järjestää uudelleen. Koska lausekkeet voivat kutsua funktioita, ja nämä funktiot voivat tarkkailla lausekkeen ulkopuolista tilaa antamalla ulkoisia kyselyitä, on mahdollista luoda skenaario, jossa laskutoimituksessa on merkitys, mutta sitä ei ole otettu huomioon lausekkeen osittaisessa järjestyksessä. Funktio voi esimerkiksi lukea tiedoston sisällön. Jos tätä toimintoa kutsutaan toistuvasti, kyseisen tiedoston ulkoisia muutoksia voidaan tarkkailla, ja siksi uudelleenjärjestely voi aiheuttaa havainnoitavissa olevia eroja ohjelman käyttäytymisessä. Tästä johtuen M-lausekkeen oikeellisuutta koskeva arviointijärjestys aiheuttaa riippuvuussuhteen tiettyihin toteutusvaihtoehtoihin, jotka saattavat vaihdella arvioijan mukaan tai saattavat vaihdella saman arvioijan mukaan vaihtelevissa olosuhteissa.
Muuttumattomuus
Kun arvo on laskettu, se on muuttumaton, joten sitä ei voi enää muuttaa. Tämä yksinkertaistaa lausekkeen arvioinnin mallia ja helpottaa tuloksen syyn arviointia, koska arvoa ei voi muuttaa sen jälkeen, kun sitä on käytetty lausekkeen myöhemmän osan arvioimiseen. Esimerkiksi tietuekenttä lasketaan vain tarvittaessa. Kuitenkin, kun se on laskettu, se pysyy kiinteänä koko tietueen elinkaaren ajan. Vaikka yritys laskea kenttä aiheutti virheen, sama virhe ilmenee uudelleen jokaisessa yrityksessä käyttää kyseistä tietuekenttää.
Tärkeä poikkeus immutable-once-calculated -sääntöön koskee luettelo-, taulukko- ja binaariarvoja, joilla on virtauttamisen semantiikka. Virtauttamisen semantiikan ansiosta M voi muuntaa tietojoukkoja, jotka eivät sovi muistiin kaikki kerralla. Suoratoiston avulla palautettavat arvot, kun tietty taulukko, luettelo tai binaariarvo luetteloidaan, tuotetaan pyydettäessä aina, kun niitä pyydetään. Koska luetteloidut arvot määrittävät lausekkeet arvioidaan aina, kun ne luetteloidaan, niiden tuottama tulos voi olla erilainen useissa luetteloinneissa. Tämä ei tarkoita sitä, että useat luetteloinnit johtavat aina eri arvoihin, vain siksi, että ne voivat olla erilaisia, jos käytettävä tietolähde tai M-logiikka ei ole deterministinen.
Huomioi myös, että funktiosovellus ei ole sama kuin arvorakenne. Kirjastofunktiot saattavat altistaa ulkoisen tilan (kuten nykyisen ajan tai kyselyn tulokset tietokannalle, joka kehittyy ajan mittaan), jonka vuoksi ne eivät ole deterministisiä. Vaikka M-funktiolla määritetyt funktiot eivät sellaisenaan paljasta mitään tällaista käyttäytymistä, ne voidaan määrittää käynnistämään muita funktioita, jotka eivät ole deterministisiä.
M-köyden lopullinen ei-deterministisen lähde on virhe. Virheet pysäyttävät arvioinnin, kun ne tapahtuvat (enintään tasolle, jolla ne käsitellään try-lausekkeella). Ei ole yleensä havaittavissa, onko a + b
aiheuttanut arvioinnin a
ennen b
tai b
ennen a
(tässä samanaikaisuus ohitetaan selvyyden vuoksi). Jos arvioitu alilauseke kuitenkin aiheuttaa virheen, voidaan määrittää, kumpi kahdesta lausekkeesta on arvioitu ensin.