Megosztás a következőn keresztül:


Alapfogalmak

Ez a szakasz a következő szakaszokban megjelenő alapfogalmakat ismerteti.

Értékek

Egyetlen adategységet nevezünk értéknek. Általánosságban elmondható, hogy az értékeknek két általános kategóriája van: a primitív értékek, amelyek atomi és strukturált értékek, amelyek primitív értékekből és más strukturált értékekből épülnek fel. Például az értékek

1 
true
3.14159 
"abc"

primitívek, mivel nem más értékekből állnak. Másrészt az értékek

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

primitív értékekből, a rekord esetében pedig más strukturált értékekből állnak.

Kifejezések

A kifejezés értékek létrehozására szolgáló képlet. A kifejezések különböző szintaktikai szerkezetek használatával alakíthatók ki. Az alábbiakban néhány példa a kifejezésekre. Minden sor egy külön kifejezés.

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

A kifejezés legegyszerűbb formája, ahogy fentebb láthattuk, egy értéket jelképező literál.

Az összetettebb kifejezések más kifejezésekből, úgynevezett alkifejezésekből épülnek fel. Példa:

1 + 2

A fenti kifejezés valójában három kifejezésből áll. A 1 és 2 a literálok a szülőkifejezés 1 + 2alkifejezései.

A kifejezésben használt szintaktikai szerkezetek által definiált algoritmust a kifejezés kiértékelésének nevezzük. Minden kifejezéstípusnak vannak szabályai a kiértékelés módjára. Egy literális kifejezés például 1 állandó értéket hoz létre, míg a kifejezés a + b két másik kifejezés kiértékelésévela ( és b) az eredményül kapott értékeket veszi fel, és néhány szabály alapján összeadja őket.

Környezetek és változók

A kifejezések kiértékelése egy adott környezetben történik. A környezetek nevesített értékek, úgynevezett változók. A környezet minden változója egyedi névvel rendelkezik a környezetben, úgynevezett azonosítóval.

A legfelső szintű (vagy gyökér) kifejezések kiértékelése a globális környezetben történik. A globális környezetet a kifejezés kiértékelője biztosítja ahelyett, hogy a kiértékelendő kifejezés tartalmából határozható meg. A globális környezet tartalma tartalmazza a szabványos kódtárdefiníciókat, és az egyes dokumentumok szakaszaiból származó exportálások befolyásolhatják. (Az egyszerűség kedvéért az ebben a szakaszban szereplő példák üres globális környezetet feltételeznek. Ez azt feltételezi, hogy nincs standard kódtár, és nincsenek más szakaszalapú definíciók.)

Az alkifejezések kiértékeléséhez használt környezetet a szülőkifejezés határozza meg. A legtöbb szülőkifejezés-típus egy alkifejezést fog kiértékelni ugyanabban a környezetben, amelyikben kiértékelték őket, de vannak, akik egy másik környezetet használnak. A globális környezet az a szülőkörnyezet , amelyen belül a globális kifejezés kiértékelése történik.

A rekord-inicializáló-kifejezés például egy módosított környezettel kiértékeli az egyes mezők alkifejezését. A módosított környezet tartalmaz egy változót a rekord egyes mezőihez, kivéve az inicializálandót. A rekord többi mezőjének belevételével a mezők a mezők értékeitől függenek. Példa:

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

Hasonlóképpen, a let-kifejezés kiértékeli az egyes változók alkifejezését egy olyan környezettel, amely a let minden változóját tartalmazza, kivéve azt, amelyik inicializálva van. A let-kifejezés kiértékeli a következő kifejezést egy olyan környezettel, amely az összes változót tartalmazza:

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

(Kiderült, hogy a rekord-inicializáló-kifejezés és a let-kifejezés ténylegesen két környezetet határoz meg, amelyek közül az egyik tartalmazza az inicializálandó változót. Ez a speciális rekurzív definíciókhoz hasznos, és az azonosítóhivatkozások között szerepel.

Az alkifejezések környezeteinek létrehozásához az új változók a szülőkörnyezet változóival "egyesítve" lesznek. Az alábbi példa a beágyazott rekordok környezeteit mutatja be:

[
    a = 
    [ 

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

Az alábbi példa egy letbe ágyazott rekord környezeteit mutatja be:

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

A változók környezettel való egyesítése ütközést okozhat a változók között (mivel a környezeti változóknak egyedi névvel kell rendelkezniük). Az ütközés a következőképpen oldható fel: ha az egyesített új változó neve megegyezik a szülőkörnyezetben meglévő változó nevével, akkor az új változó elsőbbséget élvez az új környezetben. Az alábbi példában a belső (mélyebben beágyazott) változó x elsőbbséget élvez a külső változóval xszemben.

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

Azonosítóhivatkozások

Az azonosító-hivatkozás egy környezeti változóra való hivatkozásra szolgál.

azonosító-kifejezés:
      azonosító-hivatkozás
azonosító-hivatkozás:
      kizárólagos azonosítóra mutató hivatkozás
      inclusive-identifier-reference

Az azonosítóhivatkozás legegyszerűbb formája egy kizárólagos azonosító-hivatkozás:

kizárólagos azonosító-hivatkozás:
      azonosító

Hiba, ha egy kizárólagos azonosítóra mutató hivatkozás olyan változóra hivatkozik, amely nem része annak a kifejezésnek a környezetében, amelyben az azonosító megjelenik.

Hiba, ha egy kizárólagos azonosítóra mutató hivatkozás egy jelenleg inicializált azonosítóra hivatkozik, ha a hivatkozott azonosító egy rekord-inicializáló-kifejezésben vagy let-kifejezésben van definiálva. Ehelyett egy befogadó azonosítóra mutató hivatkozással hozzáférhet az inicializálandó azonosítót tartalmazó környezethez. Ha bármely más helyzetben befogadó azonosító-hivatkozást használnak, akkor az egyenértékű egy kizárólagos azonosító-hivatkozással.

inclusive-identifier-reference:
      @ azonosító

Ez rekurzív függvények definiálásakor hasznos, mivel a függvény neve általában nem szerepel a hatókörben.

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

    x = Factorial(5) 
]

A rekord-inicializáló-kifejezéshez hasonlóan a let-kifejezésen belül egy befogadó azonosítóra mutató hivatkozás is használható az inicializálandó azonosítót tartalmazó környezet eléréséhez.

A kiértékelés sorrendje

Vegye figyelembe a következő kifejezést, amely inicializál egy rekordot:

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

A kiértékeléskor ez a kifejezés a következő rekordértéket hozza létre:

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

A kifejezés azt állítja, hogy a A + B mező számításának elvégzéséhez a mező CA és a mező B értékeinek is ismertnek kell lenniük. Ez egy példa egy kifejezés által biztosított számítások függőségi sorrendjére . Az M-kiértékelő betartja a kifejezések által biztosított függőségi sorrendet, de szabadon végrehajthatja a fennmaradó számításokat tetszőleges sorrendben. A számítási sorrend például a következő lehet:

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

Vagy a következő lehet:

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

Vagy mivel A B és nem függnek egymástól, egyszerre is kiszámíthatók:

    B = 2 + 2 egyidejűleg a A = 1 + 1
    C = A + B

Mellékhatás

Egy egyszerű és hatékony számítási modell lehetővé teszi, hogy a kifejezés kiértékelője automatikusan kiszámítsa a számítások sorrendjét olyan esetekben, amikor a kifejezés nem jelez explicit függőségeket.

Azonban támaszkodik a számítások átrendezésére. Mivel a kifejezések függvényeket hívhatnak, és ezek a függvények külső lekérdezések kibocsátásával megfigyelhetik a kifejezésen kívüli állapotot, létrehozhat egy olyan forgatókönyvet, amelyben a számítás sorrendje számít, de nem a kifejezés részleges sorrendjében van rögzítve. Előfordulhat például, hogy egy függvény beolvassa egy fájl tartalmát. Ha ezt a függvényt ismételten hívjuk meg, akkor a fájl külső módosításai figyelhetők meg, ezért az átrendezés megfigyelhető különbségeket okozhat a program viselkedésében. Az M-kifejezések helyességének megfigyeléses kiértékelési sorrendjétől függően függőséget okoz az egyes megvalósítási lehetőségektől, amelyek az egyik kiértékelőtől a másikig változhatnak, vagy eltérő körülmények között akár ugyanazon az értékelőn is változhatnak.

Módosíthatatlanság

Miután kiszámítottunk egy értéket, az nem módosítható, ami azt jelenti, hogy már nem módosítható. Ez leegyszerűsíti a kifejezés kiértékelési modelljét, és megkönnyíti az eredmény okának magyarázatát, mivel a kifejezés egy későbbi részének kiértékelése után nem módosítható az érték. A rekordmezők kiszámítása például csak szükség esetén történik. A számítás után azonban a rekord élettartamára rögzített marad. Még akkor is, ha a mező számítási kísérlete hibát eredményezett, ugyanez a hiba a rekordmező elérésére tett minden kísérletnél újra megjelenik.

A nem módosítható egyszer számított szabály fontos kivétele a streamelt szemantikával rendelkező lista-, tábla- és bináris értékekre vonatkozik. A streamelés szemantikája lehetővé teszi, hogy az M egyszerre átalakítsa a memóriába nem férő adathalmazokat. Streamelés esetén az adott tábla, lista vagy bináris érték számbavételekor visszaadott értékek igény szerint jönnek létre minden alkalommal, amikor kérik őket. Mivel az enumerált értékeket meghatározó kifejezések minden egyes számbavételkor kiértékelésre kerülnek, az általuk előállított kimenet több enumerációban eltérő lehet. Ez nem jelenti azt, hogy több enumeráció mindig eltérő értékeket eredményez, csak hogy eltérőek lehetnek, ha a használt adatforrás vagy M logika nem determinisztikus.

Azt is vegye figyelembe, hogy a függvényalkalmazás nem ugyanaz, mint az értéképítés. A kódtárfüggvények külső állapotot (például az aktuális időt vagy egy lekérdezés eredményeit) tehetnek közzé egy olyan adatbázison, amely idővel fejlődik, így azok nem determinisztikusak lesznek. Bár az M-ben definiált függvények ilyen módon nem teszik elérhetővé az ilyen nem determinisztikus viselkedést, akkor is képesek arra, hogy más, nem determinisztikus függvényeket hívjanak meg.

Az M-ben a nem determinizmus végső forrása a hibák. A hibák leállítják a kiértékeléseket,ha előfordulnak (egészen a próbakifejezés által kezelt szintig). Általában nem figyelhető meg, hogy az előző b vagy b korábbi a kiértékelést a okozta-e a + b (az egyszerűség kedvéért figyelmen kívül hagyva az egyidejűséget). Ha azonban a kiértékelt szubexpresszió először hibát jelez, akkor megállapítható, hogy a két kifejezés közül melyik lett először kiértékelve.