Sdílet prostřednictvím


Základní koncepty

Tato část popisuje základní koncepty, které se zobrazují v následujících částech.

Hodnoty

Jedna část dat se nazývá hodnota. Obecně řečeno, existují dvě obecné kategorie hodnot: primitivní hodnoty, které jsou atomické a strukturované hodnoty, které jsou tvořeny z primitivních hodnot a dalších strukturovaných hodnot. Například hodnoty

1 
true
3.14159 
"abc"

jsou primitivní v tom, že nejsou tvořeny jinými hodnotami. Na druhou stranu hodnoty

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

jsou sestaveny pomocí primitivních hodnot a v případě záznamu další strukturované hodnoty.

Výrazy

Výraz je vzorec použitý k vytvoření hodnot. Výraz lze vytvořit pomocí různých syntaktických konstruktorů. Následuje několik příkladů výrazů. Každý řádek je samostatný výraz.

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

Nejjednodušší forma výrazu, jak je vidět výše, je literál představující hodnotu.

Složitější výrazy se vytvářejí z jiných výrazů, označovaných jako dílčí výrazy. Příklad:

1 + 2

Výše uvedený výraz se ve skutečnosti skládá ze tří výrazů. Literály 1 2 jsou dílčí výrazy nadřazeného výrazu 1 + 2.

Spuštění algoritmu definovaného syntaktickými konstrukty použitými ve výrazu se nazývá vyhodnocení výrazu. Každý druh výrazu má pravidla, jak se vyhodnotí. Například literálový výraz, jako 1 je, vytvoří konstantní hodnotu, zatímco výraz a + b vezme výsledné hodnoty vytvořené vyhodnocením dvou dalších výrazů (a a b) a sečte je dohromady podle určité sady pravidel.

Prostředí a proměnné

Výrazy se vyhodnocují v daném prostředí. Prostředí je sada pojmenovaných hodnot, označovaná jako proměnné. Každá proměnná v prostředí má jedinečný název v rámci prostředí označovaného jako identifikátor.

Výraz nejvyšší úrovně (nebo kořen) se vyhodnocuje v rámci globálního prostředí. Globální prostředí poskytuje vyhodnocovač výrazů místo určení z obsahu vyhodnocovaného výrazu. Obsah globálního prostředí obsahuje standardní definice knihovny a může být ovlivněn exportem z oddílů z určité sady dokumentů. (Pro zjednodušení budou příklady v této části předpokládat prázdné globální prostředí. To znamená, že neexistuje žádná standardní knihovna a že neexistují žádné další definice založené na oddílech.)

Prostředí použité k vyhodnocení dílčího výrazu je určeno nadřazeným výrazem. Většina typů nadřazených výrazů vyhodnotí dílčí výraz ve stejném prostředí, ve které byly vyhodnoceny, ale některé budou používat jiné prostředí. Globální prostředí je nadřazené prostředí , ve kterém se vyhodnocuje globální výraz.

Výraz record-initializer-expression například vyhodnotí dílčí výraz pro každé pole s upraveným prostředím. Upravené prostředí obsahuje proměnnou pro každé pole záznamu s výjimkou pole inicializovaného. Zahrnutí ostatních polí záznamu umožňuje, aby pole závisela na hodnotách polí. Příklad:

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

Podobně výraz let-expression vyhodnotí dílčí výraz pro každou proměnnou s prostředím obsahujícím každou z proměnných let s výjimkou inicializované proměnné. Výraz let vyhodnotí výraz následující v prostředí obsahujícím všechny proměnné:

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

(Ukázalo se, že výraz inicializátoru záznamů i výraz let-expression ve skutečnosti definují dvě prostředí, z nichž jedna zahrnuje inicializaci proměnné. To je užitečné pro pokročilé rekurzivní definice a je popsán v odkazech identifikátorů .

Pro vytvoření prostředí pro dílčí výrazy jsou nové proměnné "sloučeny" s proměnnými v nadřazené prostředí. Následující příklad ukazuje prostředí pro vnořené záznamy:

[
    a = 
    [ 

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

Následující příklad ukazuje prostředí pro záznam vnořený do 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

Sloučení proměnných s prostředím může představovat konflikt mezi proměnnými (protože každá proměnná v prostředí musí mít jedinečný název). Konflikt se vyřeší následujícím způsobem: pokud je název nové sloučené proměnné stejný jako existující proměnná v nadřazeném prostředí, bude mít nová proměnná přednost v novém prostředí. V následujícím příkladu má vnitřní (hlouběji vnořená) proměnná x přednost před vnější proměnnou 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
]  

Odkazy na identifikátory

Odkaz na identifikátor slouží k odkazování na proměnnou v prostředí.

identifikátor-výraz:
      Odkaz na identifikátor
Odkaz na identifikátor:
      exclusive-identifier-reference
      inclusive-identifier-reference

Nejjednodušší forma odkazu na identifikátor je odkaz na výhradní identifikátor:

exclusive-identifier-reference:
      identifikátor

Jedná se o chybu odkazující na výhradní identifikátor odkazující na proměnnou, která není součástí prostředí výrazu, ve které se identifikátor zobrazuje.

Jedná se o chybu odkazující na výhradní identifikátor odkazující na identifikátor, který se právě inicializuje, pokud je odkazovaný identifikátor definován uvnitř výrazu record-initializer-expression nebo let-expression. Místo toho lze k získání přístupu k prostředí, které zahrnuje inicializovaný identifikátor, použít odkaz na inkluzivní identifikátor. Pokud se v jakékoli jiné situaci použije odkaz na inkluzivní identifikátor, je ekvivalentní odkazu na výhradní identifikátor.

inclusive-identifier-reference:
      @ identifikátor

To je užitečné při definování rekurzivních funkcí, protože název funkce by normálně nebyl v oboru.

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

    x = Factorial(5) 
]

Stejně jako u výrazu record-initializer-expression lze použít odkaz inclusive-identifier-reference v rámci výrazu let pro přístup k prostředí, které zahrnuje inicializovaný identifikátor.

Pořadí vyhodnocování

Představte si následující výraz, který inicializuje záznam:

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

Při vyhodnocování tento výraz vytvoří následující hodnotu záznamu:

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

Výraz uvádí, že aby bylo možné provést A + B výpočet pole C, musí být hodnoty pole A i pole B známé. Toto je příklad řazení závislostí výpočtů, které poskytuje výraz. Vyhodnocovací nástroj M se řídí pořadím závislostí poskytovaným výrazy, ale není možné provádět zbývající výpočty v libovolném pořadí, které zvolí. Například pořadí výpočtů může být:

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

Nebo to může být:

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

Nebo vzhledem k tomu A , že B a nezávisí na sobě, je možné je vypočítat souběžně:

    B = 2 + 2 souběžně s A = 1 + 1
    C = A + B

Vedlejší efekty

Povolení vyhodnocovače výrazů automaticky vypočítat pořadí výpočtů v případech, kdy výraz neobsahuje explicitní závislosti, které výraz uvádí, je jednoduchý a výkonný výpočetní model.

Spoléhá ale na schopnost měnit pořadí výpočtů. Vzhledem k tomu, že výrazy mohou volat funkce a tyto funkce můžou sledovat stav externího výrazu vystavením externích dotazů, je možné vytvořit scénář, ve kterém záleží na pořadí výpočtů, ale nezachytí se v částečném pořadí výrazu. Například funkce může číst obsah souboru. Pokud se tato funkce volá opakovaně, je možné pozorovat externí změny v daném souboru, a proto může změna pořadí způsobit pozorovatelné rozdíly v chování programu. V závislosti na takovém pozorované pořadí vyhodnocení pro správnost výrazu jazyka M způsobuje závislost na konkrétních možnostech implementace, které se mohou lišit od jednoho vyhodnocovače k dalšímu, nebo se dokonce mohou lišit ve stejném vyhodnocovače za různých okolností.

Neměnitelnost

Po výpočtu hodnoty je neměnná, což znamená, že už ji nelze změnit. To zjednodušuje model pro vyhodnocení výrazu a usnadňuje zdůvodnění výsledku, protože není možné změnit hodnotu, jakmile se použije k vyhodnocení následné části výrazu. Pole záznamu se například vypočítá pouze v případě potřeby. Jakmile se ale vypočítá, zůstane po celou dobu života záznamu pevně daný. I když pokus o výpočet pole vyvolal chybu, tato chyba se znovu vyvolá při každém pokusu o přístup k poli záznamu.

Důležitou výjimkou neměnného počítaného pravidla platí pro hodnoty seznamu, tabulky a binárních hodnot, které mají sémantiku streamování. Sémantika streamování umožňuje M transformovat datové sady, které se nevejdou do paměti najednou. Při streamování se hodnoty vrácené při vytváření výčtu dané tabulky, seznamu nebo binární hodnoty vytvářejí na vyžádání při každém vyžádání. Vzhledem k tomu, že výrazy definující výčtové hodnoty se vyhodnocují při každém jejich výčtu, výstup, který vytvoří, se může v různých výčtech lišit. To neznamená, že více výčtů vždy vede k různým hodnotám, pouze to, že se můžou lišit, pokud použitý zdroj dat nebo logika M není deterministický.

Všimněte si také, že aplikace funkcí není stejná jako konstrukce hodnot. Funkce knihovny můžou vystavit externí stav (například aktuální čas nebo výsledky dotazu vůči databázi, která se vyvíjí v průběhu času), a vykreslovat je nedeterministicky. Přestože funkce definované v jazyce M nezpřístupňují žádné takové nedeterministické chování, mohou v případě, že jsou definovány tak, aby vyvolávaly jiné funkce, které nejsou deterministické.

Konečným zdrojem ne determinismu v jazyce M jsou chyby. Chyby zastaví vyhodnocování, když k nim dojde (až na úroveň, ve které se zpracovávají výrazem try). Obvykle není pozorovatelné, zda a + b bylo způsobeno vyhodnocením a před b nebo b před a (bez ohledu na souběžnost zde kvůli jednoduchosti). Pokud však dílčí výraz, který byl vyhodnocen jako první, vyvolá chybu, lze určit, který ze dvou výrazů byl vyhodnocen jako první.