Syntaxe a sémantika programovacího jazyka Wolfram Language
Author
Albert FloresSyntaxe a sémantika programovacího jazyka Wolfram Language představuje sadu pravidel, podle nichž lze psát kód v programovacím jazyce Wolfram Language (dále jen WL), spolu s tím, jak je tento kód interpretován. Tato stránka přináší podrobnější přehled základní funkcionality, než jak je podán v článku Wolfram Language. Pokud není vysloveně uvedeno jinak, je v následujícím použita verze WL 13.0.0.
Syntaxe WL v mnohém připomíná syntaxi jiných programovacích jazyků jako C či Java. WL je case sensitive, přičemž názvy funkcí a přednastavených konstant se řídí konvencí CamelCase. +more Počáteční písmeno je tedy velké a pokud se název skládá z několika slov, tak je velké i počáteční písmeno každého slova, viz např. ListPlot, StringJoin či FunctionCompile. Pojmenovávání předdefinovaných funkcí a proměnných je ve WL poněkud rozvláčné, srovnej např. funkce SingularValueDecomposition a StandardDeviation, jejichž varianty v MATLABu zní svd a std. Navíc je obecně snaha vývojářů WL nečlenit funkce do balíčků, které by bylo potřeba před použitím importovat, ale téměř všechny funkce jazyka jsou k dispozici přímo v hlavním jmenném prostoru.
Každá funkce či konstrukt má ve WL jméno, jež často odpovídá jemu anglickému názvu. Některé z nich lze pak reprezentovat speciálními znaky, známými z jiných jazyků. +more Například sčítání se provádí znakem +, násobení znakem *, skládání řetězců znakem , apod. Této reprezentaci se říká InputForm. Tyto operace lze nicméně vyjádřit i pomocí písmen anglické abecedy. Například výraz a + b lze zapsat též jako Plus[a, b], výraz a * b jako Times[a, b], výraz "retezec 1""retezec 2" jako StringJoin["retezec 1", "retezec 2"] atd. Tato reprezentace se jmenuje FullForm. V následujícím bude často k dané funkci či operátoru zmíněna nejen obvyklá syntaxe, ale právě i její FullForm.
Základy
Identifikátory
Vývojář WL nenabízí veřejnou specifikaci toho, co může a co nemůže být identifikátor. Obecně ale nemůže být prvním znakem názvu číslice a podporována je pro znaky celá sada Unicode včetně znaků české abecedy. +more Interní konstanty a proměnné začínají konvenčně znakem dolaru $, viz např. $Output či $FontFamilies.
Na rozdíl od některých populárních jazyků nelze použít podtržítko jako součást jména proměnných či funkcí, protože je mu vyhrazena funkce ve vzorech. Pro mnoho znaků existuje ve WL jméno, které se vkládá do konstruktu \[. +more], např. \to lze získat zapsáním \[RightArrow]. Pro mnoho znaků, jako třeba písmena alfabety, též existuje alias, to jest zkratka, kterou lze zapsat mezi dvěma stisknutími klávesy , aby se vytvořil odpovídající znak. Znaky lze vkládat i pomocí jejich jmen v jazyce HTML či systému TeX způsobem podobný aliasům, a tak např. á vrátí á, \infty vrátí \infty apod. Konečně, libovolný znak Unicode lze vložit vypsáním \:nnnn či \|nnnnnn, kde nnnn či nnnnnn je hexadecimální kódový bod daného znaku.
Komentáře
Na rozdíl od některých jazyků jako např. C++ či Java existuje ve WL jen jeden druh komentářů, kde je text komentáře uzavřen mezi kulaté závorky s hvězdičkami:
a = 1; (* toto je komentář *) (* komentář může přesahovat několik řádek *) b = a + 2;
Předešlé výstupy
Jádro WL udržuje přehled o výsledcích všech předešlých příkazů odeslaných uživatelem z front endu. Vyvolat hodnotu posledního příkazu lze symbolem procenta. +more Tak například volání.
1+2; %
vrátí hodnotu 3. Chceme-li vyvolat předposlední výsledek, napíšeme znak procent dvakrát (%%); pro výsledek třetí od konce napíšeme tento znak třikrát atd. +more Každému výstupu je navíc přiřazeno číslo, které je pro daný běh jádra jedinečné a tak pokud víme číslo daného výstupu, řekněme 51, lze odpovídající výstup vyvolat napsáním %51.
Nápověda
Krátkou nápovědu k danému symbolu lze programově zobrazit v editoru napsáním otazníku na začátku řádku, následovaným jménem symbolu. Krátký popis funkce sinus tak lze obdržet voláním:
?Sin
Pokud místo jednoho otazníku použijeme otazníky dva, obržíme detailnější nápovědu (. Sin). +more Programové volání nápovědy lze rozšířit o žolíkové znaky, kde * označuje libovolný počet libovolných znaků a @ označuje libovolné malé písmeno. Tak například volání . P*i vrátí ve verzi 13. 1. 0 dva nálezy a sice Pi a PrimePi. Hledání lze tímto způsobem dále rozšířit na celé jmenné prostory. K vypsání všech symbolů definovaných ve jmenném prostoru (kontextu) Global stačí napsat:.
?Global`*
Datové typy
Jedním za základních designových principů WL je ten, že „vše je výraz“. Výraz, anglicky expression, je buď atomární, viz níže, anebo normální, a pak má obecný tvar
hlava[arg1, arg2, ...]
kde hlava je hlavička výrazu, jíž lze dostat voláním funkce Head, a kde za hlavičkou následuje v hranatých závorkách nula či více výrazů oddělených čárkami. Tento obecný tvar sledují konstrukty typu If či For, volání funkcí, specifikace stylu apod. +more Hlavička samotná může být buď symbol, např. název funkce, anebo další výraz. Takovým případem může být např. výraz (#&)[x], který má za hlavičku ryzí funkci #&, jež je samotná specifikována interně výrazem Function[Slot[1]].
Dokonce i zápis tvaru něco; něco2; něco3 je vyhodnocen jako výraz a sice výraz tvaru CompoundExpression[něco, něco2, něco3]. Výrazy lze do sebe vnořovat a vytvářet tak strukturovaná data a kód. +more Podvýraz na jisté úrovni vnoření lze získat pomocí funkce Level. Rozvětvení pomyslného stromu vnořených výrazů lze kvantifikovat pomocí funkce LeafCount. Jisté konstrukty, jako čísla či řetězce, jsou považovány za atomární a stojí na posledním stupínku vnoření. Tyto jsou představeny v sekcích níže. Viz též následující oddíl #Datové struktury|„Datové struktury“.
Symboly
Jedním ze základních typů ve WL jsou symboly, to jest výrazy s hlavičkou Symbol. Funkce (kromě těch ryzích), předdefinované konstanty atd. +more jsou symboly. Na rozdíl od jiných jazyků jako C či Python nejen že nemusí být proměnná inicializována, ale nemusí mít ani přiřazenu žádnou hodnotu, a tak například následující vstupní kód je bez problémů ve WL interpretován.
x
Dokud není do proměnné uložena konkrétní hodnota, tak se tato chová jako symbolická proměnná, kterou lze využít pro symbolické výpočty, a tak např.
y = x + 2; y^2 (* vrátí: (2 + x)^2 *) Expand[y^2] (* vrátí: 4 + 4 x + x^2 *)
kde funkce Expand rozepisuje mocniny výrazů do jednotlivých členů.
Chceme-li vymazat hodnotu proměnné var, lze toto učinit buď zápisem x = . , či voláním Clear[x]. +more Tento přístup pouze smaže hodnotu proměnné, ponechá nicméně její jméno k dispozici výpočetnímu jádru. Pokud chceme proměnnou vyjmout úplně, lze toto provést funkcí Remove. Název symbolu nemůže mj. začínat číslicí, nesmí obsahovat podtržítka, může ale např. obsahovat znaky české abecedy.
Čísla
WL má několik číselných datových typů, Integer odpovídá celým číslům, Rational racionálním číslům, Real číslům reálným a Complex číslům komplexním. Poslední dva typy jsou typy s pohyblivou řádovou čárkou. +more Jakmile jsou vstupní hodnoty funkcí typu Integer či Rational, snaží se WL spočíst výsledek naprosto přesně, to jest s nekonečnou přesností. To ale může vést k neúměrně dlouhému výpočtu. Srovnej následující kód:.
x = 3; (* 3 je typu Integer *) x^2 + Sqrt[x] (* vrátí 9 + Sqrt[3] *) y = 3.; (* 3. je typu Real *) y^2 + Sqrt[y] (* vrátí 10.7321 *)
Vědecký zápis čísel pomocí mantisy a exponentu, který má v mnoha jazycích syntaxi ve stylu 12. 34e3 se ve WL provede způsobem 12. +more34*^3. Pokud je počáteční číslice desetinného čísla rovna nule, lze tuto vynechat a tedy . 1 je totéž co 0. 1. Čísla lze zadávat i v jiné než desítkové soustavě (podporovány jsou soustavy o základu 2 až 36) a to tak, že se před číslo uvede základ soustavy následovaný dvěma stříškami: 2^^101 je binární zápis čísla 5, 16^^ff je šestnáctkový zápis čísla 255 apod.
Přesné výrazy lze převést na floating-point výrazy voláním funkce N, kde lze jako druhý nepovinný parametr uvést přesnost výsledného výrazu. WL rozlišuje absolutní přesnost čísel (Accuracy) a relativní přesnost (Precision). +more Při zápisu čísla lze Accuracy udat jako číslo za dvěma zpětnými apostrofy ``, Precision pak jako číslo za apostrofem jedním `:.
3. 14``20 (* Accuracy je 20 *) 3. +more14`20 (* Precision je 20 *) 3. 14 (* Accuracy a Precision mají výchozí hodnoty dané strojem, na kterém WL běží *) 3 (* Accuracy i Precision jsou nekonečné *) N[(1 + Sqrt[2])/5] (* vrátí: 0. 482843 *).
Číslům s pohyblivou řádovou čárkou lze nastavit libovolně velkou přesnost. Pokud tato nicméně překročí přesnost stroje, na kterém WL běží, je vyšší přesnosti interně docíleno softwarovými prostředky, což může velmi zpomalovat výpočetní jádro. +more Všechny dosud uvedené notace lze kombinovat a tak například zápis 2^^10011. 1011`8*^3 označuje číslo 158.
Ve WL je předdefinováno množství konstant jako nekonečno (Infinity), jež lze dostat například dělením nenulového čísla nulou, nerozhodnutelné (Indeterminate), jež lze dostat dělením nuly nulou, $MachineEpsilon, jež označuje nejmenší rozlišitelné číslo, $MaxMachineNumber, jež označuje největší reprezentovatelné floating-point číslo atd. Podporováno je i mnoho matematických konstant jako číslo pí (Pi), eulerovo číslo (E), zlatý řez (GoldenRatio), atd.
Řetězce
Textové řetězce jsou uvozeny dvojitými uvozovkami, jednoduché uvozovky použít nelze. Podobně jako pro názvy proměnných a funkcí, i v řetězcích lze použít libovolné Unicode znaky včetně písmen české abecedy. +more Jsou podporovány některé typické escape sekvence jako uvozovky \", odřádkování \n či tabulátor \t. Podporována je řada operací na řetězcích. Například zřetězení dvou (a více) textových řetězců r1 a r2 lze provést voláním r1r2 či ekvivalentně StringJoin[r1, r2]. Získání znaku na daném místě řetězce lze provést funkcí StringPart. A tak například:.
"Příklad řetězce" "Začátek""Konec" (* vrátí: "ZačátekKonec" *) "První řádek\nDruhý řádek" (* vypíše odřádkovaný řetězec *) StringPart["abcd", 2] (* vrátí: "b" *)
Obecný výraz lze přeměnit na řetězec voláním funkce ToString. Opačně, je-li v řetězci uložen platný kód, lze tento řetězec na kód převést funkcí ToExpression. +more Řetězce lze vypisovat pomocí funkce Print, která přijímá i neřetězcové výrazy, na něž tedy není třeba volat zvlášť ToString, přičemž tyto výrazy jsou vykresleny ve své původní formě. Chceme-li do řetězce dosadit parametry, lze buď použít funkci StringForm nebo novější funkci StringTemplate, která nabízí širší možnosti za cenu složitějšího zápisu. Lze pak psát například:.
ToString[StringForm["Součtem `1` a `2` obržíme `3`. ", 2, 3, 5]] (* vrátí: "Součtem 2 a 3 obržíme 5. +more" *) StringTemplate["Součtem `1` a `2` obržíme `3`. "][2, 3, 5] (* vrátí: "Součtem 2 a 3 obržíme 5. " *).
Na rozdíl od jiných jazyků jsou podporovány i složitější konstrukty uvnitř řetězců, které umožňují pokročilejší formátování výstupu. Například zlomek „a / b“, kde je čitatel přímo nad jmenovatelem tak, jak je běžné v matematické notaci, lze zapsat do řetězce jako "\. +more\(\*FractionBox[\(a\), \(b\)]\)". Uživatel s touto nízkoúrovňovou reprezentací nicméně nepracuje, protože v editoru se zobrazí pouze samotný zlomek. Dále WL podporuje řetězcové vzory (angl. string patterns), což jsou obdoby regulárních výrazů z jiných jazyků, viz oddíl #Regulární výrazy|„Regulární výrazy“.
Datové struktury
Základní datovou strukturou ve WL je pole představované konstruktem List, k níž se od verze 10. 0 přidalo asociativní pole (hashovací tabulka) představované konstruktem Association. +more Oba jsou podrobně představeny níže. WL podporuje ale i další druhy datových struktur jako řídká pole (SparseArray), pole s dodatečnými symetriemi (SymmetrizedArray), pole s fyzikálními jednotkami (QuantityArray), či řadu tradičních struktur, jež lze obdržet jako speciální případ konstruktu DataStructure. Na rozdíl od některých jiných jazyků nemá WL datový typ odpovídající množinám, kam by šel daný prvek vložit pouze jednou.
List
Pole je datová struktura, jejíž prvky mohou být různých typů - od čísel, přes řetězce, po obrázky či zvukové záznamy. Prvkem může být i další pole, čímž lze vytvářet vícerozměrná pole. +more Pole se zapisují pomocí složených závorek {prvek1, prvek2, prvek3, . , prvekN}, kde jsou jednotlivé prvky odděleny čárkou. Pole je ve WL představováno výrazem s hlavičkou List, znamenající anglicky seznam. Dvojrozměrné pole celých čísel může vypadat třeba takto:.
p = {{5, 1, 3}, {7, 0}, {2, 1, 6, 8}, {-3, 1, 1}}
Zdůrazněme, že počet prvků nemusí být v každém vnořeném poli stejný. Počet prvků lze zjistit příkazem Length. +more Je-li počet prvků v každém vnořeném poli shodný, lze tento počet pro každou dimenzi zjistit příkazem Dimensions.
Indexování pole se provádí zapsáním dvojitých hranatých závorek, do kterých se uvede index, přičemž indexování probíhá od jedničky. Pro získání druhého vnořeného pole v poli p definovaném výše tak lze zapsat
. Indexovat lze i od konce pomocí záporných čísel. Poslední prvek tak lze obdržet voláním
, předposlední
atd. Chceme-li namísto jediného prvku získat rozsah prvků od indexu i1 po index i2, stačí zapsat
, kde jsou mezi indexy vloženy dva středníky. Konstrukt
vrátí pak každý k-tý prvek v daném rozsahu. Pokud namísto rozsahu chceme dostat jen několik vybraných prvků, lze tyto obdržet jediným voláním tvaru
, kde jsou indexy jednotlivých prvků ohraničeny složenými závorkami. V případě dvourozměrných polí lze indexovat dvěma způsoby - buď stylem
, nebo kompaktněji
. Oba způsoby lze použít i pro vícerozměrná pole. Změnit hodnotu daného prvku pak lze přiřazením ve tvaru:
p3, 2 = 42;
Takovéto přiřazení upravuje seznam in place.
Interně je pole reprezentováno dvěma různými způsoby v závislosti na typu dat, která obsahuje. V obecném případě obsahuje pole pouze adresy na jednotlivé části paměti, ve kterých jsou uloženy prvky samotné. +more Pokud je ale typ všech prvků (v jedno- i vícerozměrných polích) stejný a číselný a současně je počet prvků v každé dimenzi shodný, může WL pro zvýšení výkonu použít efektivnější reprezentaci označovanou jako PackedArray, která je více podobná způsobu, jakým je pole reprezentováno např. v jazyce C jako souvislý blok paměti.
Pole podporují operace jako řazení (Sort), vektorové operace jako vektorový součin (Cross) či množinové operace jako sjednocení (Union). Dvourozměrná pole lze interpretovat jako matice - v takových případech lze použít maticové operace jako maticový součin (Dot[A, B] pro matice A a B, popř. +more totéž zkráceně pomocí tečky A. B), determinant (Det), apod.
Association
Asociativní pole jsou imutabilní datové struktury zavedené ve verzi 10. 0 a jsou představována výrazem Association[k1->h1, k2->h2, . +more, kN->hN] či ekvivalentně zápisem h1, k2->h2, . , kN->hN|>, kde k1 atd. jsou klíče a h1 atd. jsou jim odpovídající hodnoty. Za klíč může přitom sloužit libovolný výraz. Seznam klíčů lze obdržet voláním funkce Keys, jim odpovídající hodnoty pak funkcí Values.
Pokud chceme dostat hodnotu pro klíč k v asociativním poli a, píšeme a[k] s jednoduchými hranatými závorkami. Na rozdíl od jiných jazyků si v WL asociativní pole uchovává i informaci o pořadí svých prvků a tak na něj lze použít i indexování známé ze seznamů. +more Máme-li asociativní pole tvaru a = 3, "s"->5, "t"->7, "u"->9|>, lze hodnotu 7 obdržet buď voláním a["t"] či indexováním .
, protože je pár ("t", 7) třetím prvkem v asociativním poli a. Oba způsoby lze zkombinovat tak, že se pro indexování použije místo indexu samotný klíč, obalený do výrazu Key, a sice
Tento hybridní zápis je užitečný ve chvíli, kdy je asociativní pole prvkem nějakého seznamu a/nebo je hodnota pro daný klíč seznamem obsahující další prvky. +more Máme-li tedy například seznam tvaru:.
s = {3, 2, {8, "retez"}, "x"->42, y->Sin|>, "a"}
lze hodnoty "retez" a 42 obdržet voláním
s[[3, Key[5], 2]] (* vrátí "retez" *) s3, "x" (* vrátí 42 *)
V posledním řádku je využit fakt, že pokud je klíčem řetězec, lze hlavičku Key vynechat. Asociativní pole nepodporují jen Rule, ale i odložené RuleDelayed, kterýžto rozdíl se projeví například při použití funkcí jako RandomReal:
a = RandomReal[]|>; a[k] (* vrátí 0.778739 *) a[k] (* vrátí 0.003326 *)
Asociativní pole lze kromě manuálního vypsání vytvořit různými způsoby. Máme-li například seznam výrazů {e1, . +more, eN}, pro něž chceme spočíst nějakou vlastnost a výsledná data pak uložit do asociativního pole, lze použít funkci AssociationMap, která vezme jistou funkci f a tu aplikuje zvlášť na každý výraz. Výsledkem je pak asociativní pole tvaru f[e1], . , eN->f[eN]|>, kde klíče jsou původními výrazy a jim odpovídající hodnoty jsou návratové hodnoty funkce f. Podobně, máme-li seznam klíčů {k1, . , kN} a zvlášť seznam hodnot {h1, . , hN}, lze tyto přetvořit do asociativního pole voláním ve tvaru AssociationThread[{k1, . , kN} -> {h1, . , hN}], jež vrátí výraz h1, . , kN->hN|>.
Obyčejně jsou funkce aplikovány na hodnoty asociativního pole, klíče jsou přeskakovány. Pokud chceme aplikovat danou funkci jen na klíče, lze toto učinit pomocí funkce KeyMap. +more Chceme-li manipulovat s celým párem (klíč, hodnota), lze použít funkci KeyValueMap. V ryzích funkcích lze navíc místo pozičního slotu použít slot pojmenovaný po daném klíči. Uvažme například seznam asociativních polí {a1, a2, . , aN}, z nichž každé obsahuje klíč "klic", kde naším úkolem je získat seznam hodnot odpovídajících tomuto klíči. Toto lze učinit kódem #klic & /@ {a1, a2, . , aN}, kde #klic je slot ryzí funkce.
Asociativní pole h1, k2->h2, . , kN->hN|> může svým zápisem velmi připomínat seznam {k1->h1, k2->h2, . +more, kN->hN}, jehož prvky jsou výrazy Rule tvaru klič->hodnota. Takovýto seznam nicméně nepodporuje vyhledání hodnoty pomocí jejího klíče. Chování asociativního pole lze do jisté míry emulovat použitím indexovaných proměnných (angl. indexed variable), což jsou proměnné, pro něž jsou definovány výrazu tvaru proměnná[klíč] = hodnota; např. :.
a[1] = foo; a["asdf"] = bar;
V tomto případě nemá symbol a přiřazenu žádnou hodnotu. Hodnotu mají přiřazenu jen výrazy a[1] a a["asdf"].
Operátory
Aritmetika
WL podporuje tradiční aritmetické operace s čísly jako sčítání (a + b), odčítání (a - b), násobení (a * b), dělení (a / b), spolu s unárními operaci ve stylu jazyka C jako inkrement (a++, ++a). Umocňování se značí stříškou (a^b) a pro celočíselné dělení a modulo žádné zkrácené zápisy neexistují a lze místo nich použít funkce Quotient a Mod. +more Znak násobení * lze vynechat, mezery se tak vyhodnocují automaticky jako násobení.
Vektorový součin odpovídá funkci Cross, maticové násobení odpovídá funkci Dot a zapisuje se tečkou (a . b). +more Vynásobení vektoru či matice číslem se provádí po prvcích a tak např. 3 * {a, b, c} vrátí {3 a, 3 b, 3 c}. Podobně se násobení chová i při (skalárním) násobení matice vektorem: {a, b, c} * {{1, 2}, {3, 4}, {5, 6}} vrátí {{a, 2 a}, {3 b, 4 b}, {5 c, 6 c}}, zatímco maticové vynásobení {a, b, c} . {{1, 2}, {3, 4}, {5, 6}} vrátí {a + 3 b + 5 c, 2 a + 4 b + 6 c}.
Kromě tradičních operátorů obsahuje WL i množství operátorů bez předdefinovaného chování. Jedním takovým je NonCommutativeMultiply, jenž lze zapsat jako dvě hvězdičky **. +more Pomocí UpValues lze tomuto operátoru dodefinovat aritmetická pravidla, podle kterých se má chovat. Konstrukt a ** b tak poté třeba může představovat nekomutativní součin proměnných a a b.
Přiřazení
WL nabízí dva druhy přiřazení - přímé (striktní, výraz Set) a odložené (nestriktní, výraz SetDelayed). Při přímém přiřazení je příkazem var = hod do proměnné var na levé straně přiřazena aktuální hodnota hod na straně pravé. +more Naproti tomu odložené přiřazení var := hod hodnotu na pravé straně nevyhodnocuje až do chvíle, kdy je proměnná volána. Rozdíl mezi těmito dvěma přiřazeními je dobře patrný, je-li do proměnné přiřazena náhodná hodnota funkcí RandomReal a tato proměnná je následně několikrát po sobě volána:.
x = RandomReal[]; y := RandomReal[]; {x, y} (* vrátí {0.211393, 0.882601} *) {x, y} (* vrátí {0.211393, 0.303523} *) {x, y} (* vrátí {0.211393, 0.196294} *)
Přímé přiřazení se používá pro definici konstant a proměnných, odložené přiřazení se pak běžně využívá při definicích funkcí. Viz též sekci #Funkce|„Funkce“.
Přiřazení lze i řetězit a tak lze psát např. a = b = c = 42. +more Lze přiřazovat i do několika proměnných současně pomocí seznamů: {a, b, c} = {1, 2, 3}. Tímto způsobem lze přehodit hodnoty dvou proměnných: {a, b} = {b, a}. Podporovány jsou i kombinace aritmetických operací s přiřazením ve stypu jazyka C: +=, *=, /=, atd.
Porovnávání
WL obsahuje tradiční porovnávací operátory jako „větší než“ (>), „menší než“ , „větší nebo rovno“ (>=) a „menší nebo rovno“ . Tyto vztahy odpovídají po řadě funkcím Less, LessEqual, Greater a GreaterEqual. +more Vztah „rovná se“ se zapisuje dvěma rovnítky (==, funkce Equal) a vztah „nerovná se“ se zapisuje vykřičníkem následovným rovnítkem (. =, funkce Unequal). Všechny následující výrazy jsou vyhodnoceny jako pravdivé:.
3 > 2; -1 = 2; 1
Kromě testu na rovnost poskytuje WL i test na identitu, jenž se zapisuje třemi rovnítky (===, funkce SameQ) a jehož opak je vyjádřen symbolem =. = a funkcí UnsameQ. +more Zatímco rovnost == testuje, zda jsou si dvě čísla numericky rovna, identita === zjišťuje, zda se jedná o skutečně stejná čísla. Tak například výraz 2 == 2. 0 vrátí True, protože celé číslo 2 typu Integer je numericky rovno reálnému číslu 2. 0 typu Real, avšak 2 === 2. 0 vrací False, protože se jedná o dva různé typy. Obdobně, máme-li dvě proměnné x a y, jimž nebyly dosud přiřazeny žádné hodnoty, tak výraz x == y zůstane nevyhodnocen, protože nelze určit, zda si dvě hodnoty jsou rovny, zatímco x === y vrátí rovnou False.
Kromě výše uvedených funkcí jako Equal či Greater, které berou dva parametry, poskytuje WL i jejich operátorové podoby, kde je dosazen pouze parametr první. Místo zápisu Equal[x, y] (jenž je ekvivalentní zápisu x == y) lze psát EqualTo[x][y], kde EqualTo je operátorová obdoba funkce Equal. +more Výraz EqualTo[x][y] je nutno číst jako funkci EqualTo[x] (parametrizovanou proměnnou x) aplikovanou na proměnnou y. Operátorové podoby srovnávacích funkcí lze například využít ve chvíli, kde chceme porovnávat celé pole čísel s jednou jedinou hodnotou. Tak například:.
EqualTo[3] /@ {1, 2, 3, 4, 5, 6} (* vrátí {False, False, True, False, False, False} *) GreaterThan[3] /@ {1, 2, 3, 4, 5, 6} (* vrátí {False, False, False, True, True, True} *)
kde GreaterThan je operátorová forma funkce Greater.
Logické operátory
Pravdivostní hodnoty pravda a nepravda jsou představovány konstantami True a False. Základní logické operace jsou pak zadány těmito funkcemi: konjunkce pomocí And (místo And[a, b] lze psát též a && b), disjunkce pomocí Or (a || b) a negace pomocí Not (. +morea). Funkce And a Or jsou vyhodnocovány zkráceně a tak je-li výsledná pravdivostní hodnota známa dříve, než se vyhodnotí všechny výrazy, nejsou tyto vyhodnoceny. Podporovány jsou i další logické operace jako Xor, Nand, Implies, atd. Ve WL neexistují speciální znaky pro bitové logické operace a je třeba použít názvy odpovídajících funkcí jako BitAnd, BitOr, BitNot, atd.
WL podporuje i kvantifikátory pro všechny (ForAll) a existuje (Exists). Komplikované logické výrazy lze zjednodušit pomocí funkcí Resolve, BooleanConvert či Simplify. +more Některé výrazy nelze vyhodnotit ani jako pravdu či nepravdu. Takové výrazy jsou programem posílány nevyhodnocené. Chceme-li vynutit jejich vyhodnocení (na False v případě nerozhodnutelných výrazů), lze je obalit do funkce TrueQ. Pro převod pravdivostní hodnoty na číslo lze použít funkci Boole, která převede True na 1 a False na 0. Ve WL neexistuje datový typ odpovídající typu bool či boolean z jiných programovacích jazyků a pokud je třeba specifikovat, že daná proměnná var nabývá pouze pravdivostních hodnot, lze psát Element[var, True|False].
Řídicí struktury
Podmínky
Podmínky lze implementovat různými způsoby. Nejčastějším je patrně konstrukt If, jehož základní syntaxe zní If[podm, vyraz1, vyraz2], kde podm je podmínka, která je buď pravda (True), v kterémžto případě se vyhodnotí vyraz1 či nepravda (False), v kterémžto případě se vyhodnotí vyraz2. +more Např.
x = 2; If[x Podmínky jsou na rozdíl od populárních jazyků jako C či Python představovány výrazem, který lze vyhodnotit. Lze tak předchozí kód přepsat do tvaru
x = 2; y = If[x
Na rozdíl od některých jiných jazyků, If má tři argumenty, přičemž třetí argument je vyhodnocen, nelze-li určit pravdivostní hodnotu prvního argumentu. Pro příklad uvažme, že proměnná x nemá přiřazenu žádnou hodnotu a nelze tak určit, zda je menší nebo větší než jedna:
y = If[x
Řetěz If výrazů lze nahradit funkcí Switch, podobně jako v jiných jazycích, jejíž syntaxe zní Switch[vstup, vzor1, vyraz1, vzor2, vyraz2, . , vzorN, vyrazN]. +more První argument vstup je vyhodnocen a výsledná hodnota je porovnávána postupně s výrazy vzor1, vzor2, atd. Ve chvíli, kdy je nalezena shoda mezi hodnotou vstup a jistým vzorem vzorj, je vyhodnocen kód vyrazj a běh programu je poté přenesen za konec výrazu Switch. Jako vzor1 až vzorN lze použít obecné vzory a není tedy nutná přesná shoda mezi vzorj a vstupní hodnotou. Roli výchozího chování, které je např. v jazyce Java umožněno klíčových slovem default, plní vzor _, který lze umístit na pozici argumentu vzorN. Chceme-li tedy například udat slovní hodnocení na základě školní známky s tím, že pro známky mimo rozsah vypíšeme chybovou hlášku, můžeme psát:.
Switch[znamka, 1, "výborně", 2, "chvalitebně", 3|4|5, "příště se lépe připrav", _, "neplatná známka" ]
V případě, že znamka je 3 nebo 4 nebo 5 vrátí Switch jako návratovou hodnotu řetězec "příště se lépe připrav". Pokud není známka celé číslo mezi 1 a 5, tak Switch vrátí řetězec "neplatná známka".
Ve WL existuje i funkce Which se syntaxí Which[podm1, vyraz1, podm2, vyraz2, . , podmN, vyrazN], ve které dochází postupně k vyhodnocování podmínek podm1, podm2, atd. +more a ve chvíli, kdy je daná podmínka podmj vyhodnocena jako True, tak se provede za ní specifikovaný kód vyrazj. Roli klíčového slova default zde pak může plnit literál True vložený jako poslední podmínka podmN. Chceme-li tedy například určit denní dobu v závislosti na hodině zadané v proměnné hod a současně vrátit chybové hlášení v případě, že hod není v rozmezí 0-24, můžeme psát:.
Which[ 0
Cykly a jejich ekvivalenty
WL nabízí cykly typické pro další programovací jazyky, jako for cyklus (For), while cyklus (While) a do-while cyklus (reprezentovaný příkazem Until uvedeným ve verzi 13. 1). +more Syntaxe for cyklu je velmi blízká syntaxi pro tento cyklus v jazyce C (konkrétně For[počátek, konec, inkrement, tělo]). Používat tento příkaz se nicméně nedoporučuje a místo toho je upřednostňováno používání specializovanějších příkazů, z nichž některé jsou uvedeny níže.
Je-li cílem provést tutéž akci pro předem daný počet indexů, lze použít funkci Do, jejíž syntaxe zní Do[. kód potenciálně závisející na i. +more, {i, start, konec}]. Pokud se argument start vynechá, index i jde od jedničky. Vypsání tří po sobě jdoucích čísel 1, 2, 3 tak lze provést kódem Do[Print[i], {i, 3}]. Je-li naopak cílem vytvořit pole hodnot na základě jistého předpisu, lze použít příkaz Table nebo Array, jejichž použití zní:.
Table[a[i], {i, 3}] (* vrátí: {a[1], a[2], a[3]} *) Array[a, {3}] (* vrátí: {a[1], a[2], a[3]} *)
Funkce Table umožňuje místo indexu coby číselného pořadí použít přímo prvky pole a napodobuje tak chování konstruktu foreach z jiných jazyků. Srovnej:
seznam = {"a", "b", "c"}; Table[str"x", {str, seznam}] (* vrátí: {"ax", "bx", "cx"} *)
Vícerozměrná pole lze vytvořit příkazem Table, kde je uveden příslušný počet indexových proměnných s odpovídajícími rozsahy. Například:
Table[a[i, j], {i, 2}, {j, -1, 1}] (* vrátí: {{a[1, -1], a[1, 0], a[1, 1]}, {a[2, -1], a[2, 0], a[2, 1]}} *)
Poznamenejme, že místo příkazu Do lze použít funkci Scan a podobně místo Table lze použít funkci Map. Výše uvedený příklad lze přepsat do tvaru:
Map[a, Range[3]] (* vrátí: {a[1], a[2], a[3]} *) a /@ Range[3] (* vrátí: {a[1], a[2], a[3]} *)
kde Range[n] vrací pole čísel tvaru {1, 2, 3, . , n}. +more Druhý řádek je pouze kompaktní zápis řádku prvního, se kterým je ekvivalentní. Používáním funkce Map lze elegantně provádět stejné operace jako s Table s tou výhodou, že není třeba používat explicitně indexovou proměnnou.
Další častou situací je, když je cyklus použit pro opakovanou aplikaci téže funkce na jistou počáteční hodnotu. Tento případ lze ve WL řešit použitím funkce Nest, jejíž první parametr udává funkci, jež má být aplikována, druhý parametr udává počáteční hodnotu a parametr třetí pak počet opakování:
Nest[f, x, 3] (* vrátí: f[f[f[x]]] *)
Potřebujeme-li v každém opakování zvolit dodatečnou hodnotu, lze místo Nest použít funkci Fold, jejíž první parametr je aplikovaná funkce, parametr druhý je počáteční hodnota a parametr třetí je seznam dodatečných hodnot
Fold[f, x, {a, b, c}] (* vrátí: f[f[f[x, a], b], c] *)
Výjimky
Vyhodnocování kódu lze programově dočasně přerušit funkcí Interrupt, která vyvolá dialogové okno, v němž může uživatel určit, jak dále postupovat. Ukončit okamžitě vyhodnocování lze programově funkcí Abort, jež vrátí hodnotu $Aborted. +more Některé funkce při nesplnění očekávané akce vrátí $Failed. Přerušit standardní tok vyhodnocování příkazů lze vložením výrazu Throw na dané místo kódu. Tento výraz musí být posléze zachycen funkcí Catch, do níž je zabalen dotčený kód, viz např. :.
Catch[prikaz1; prikaz2; Throw[aha]; prikaz3] (* vrátí: aha *)
Kód může vracet i zprávy příkazem Message. Tyto zprávy mohou být zachycovány funkcí Check. +more Zpráva pro daný symbol f se specifikuje syntaxí f::jmenozpravy = "text zprávy". Šíření dané zprávy z konkrétního výrazu lze potlačit pomocí funkce Quiet, potlačení zprávy či skupiny zpráv v rámci celého systému lze funkcí Off a její znovuzprovoznění lze provést funkcí On. Srovnej funkci:.
deleni::delnul = "Dělení nulou"; (* definice chybové zprávy *) deleni[a_, b_] := If[b != 0, a/b, Message[deleni::delnul];$Failed]; (* definice funkce *)
a její volání pro různé vstupní hodnoty:
deleni[3, 2] (* vrátí: 3/2 *) deleni[3, 0] (* vypíše chybovou hlášku "Dělení nulou" a vrátí: $Failed *) Quiet[deleni[3, 0]] (* nevypíše chybovou hlášku a vrátí: $Failed *) Check[deleni[3, 0], "příště neděl nulou"] (* vypíše chybovou hlášku "Dělení nulou" a vrátí: "příště neděl nulou" *)
Použít lze i funkci Assert, která vyvolá chybovou zprávu ve chvíli, kdy podmínka specifikovaná uvnitř Assert nevrátí True. Pro zjišťování hodnot proměnných a výrazů uvnitř větších bloků kódu lze užít funkci Echo a její příbuzné.
Ve verzi 12. 2 byla zavedena modernější sada funkcí v čele s funkcemi Confirm a Enclose. +more Tyto funkce při neúspěchu vrátí výraz Failure, jehož tělo obsahuje doplňující informace o chybě. Funkci deleni z příkladu výše lze s pomocí funkcí ConfirmBy a Enclose přepsat do tvaru.
deleni[a_, b_] := Enclose[a/ConfirmBy[b, # . = 0 &, "Dělení nulou"]] (* definice funkce spolu s chybovým hlášením *) deleni[3, 2] (* vrátí: 3/2 *) deleni[3, 0] (* vrátí: Failure[. +more], jenž obsahuje doplňující informace o chybě včetně hlášky "Dělení nulou" *).
Vzory a nahrazovací pravidla
Vzory
Jedním ze specifik WL je podpora široké škály vzorů (angl. patterns), což jsou svým způsobem prototypy výrazů a lze je chápat jako regulární výrazy aplikované na kód a data kódem zpracovávaná. +more S jejich pomocí lze vyhledávat části kódu či zpracovávaných dat a nahrazovat tyto kódem jiným.
Například podtržítko _ označuje libovolný výraz, dvě podtržítka __ označují posloupnost jednoho a více výrazů a tři podtržítka ___ označují posloupnost libovolného nezáporného počtu výrazů. Tyto a podobné vzory lze použít například při zjišťování, zda daný výraz vyhovuje jistým podmínkám, či k provádění úprav dat způsobem, který připomíná práci funkcí. +more Pokud chceme například zjistit, zda je zadaný seznam sez neprázdný, lze toto provést voláním MatchQ[sez, {__}], kde vzor {__} označuje seznam s alespoň jedním prvkem a funkce MatchQ zjišťuje, zda daný výraz, zde sez, vyhovuje danému vzoru.
Každý výraz ve WL má hlavičku. Tuto lze specifikovat připojením jejího názvu za podtržítko. +more Chceme-li tedy zjistit, zda daný seznam sez obsahuje pouze reálná čísla, lze toto provést voláním MatchQ[sez, {___Real}], kde ___Real označuje posloupnost libovolného počtu reálných čísel. Části vzoru lze i přiřadit jméno, což je výhodné při použití v pravidlech a definicích funkcí. Funkce se běžně definují způsobem: f[x_] := (nějaký kód závislý na x), kde konstrukt x_ je vzor označující libovolný výraz, jemuž je přiřazeno jméno x. V případě složitějších vzorů lze použít místo podtržítek tečky a jméno se pak udává volitelně před dvojtečku. Například konstrukt x:({a, b}. ) označuje vzor pojmenovaný x, který odpovídá posloupnosti jednoho či více seznamů tvaru {a, b}.
Množinu výrazů vyhovujících danému vzoru lze úžeji specifikovat pomocí podmínek (Condition) a testovacích funkcí (PatternTest). Například vzor x_List/;Length[x] označuje seznam s nanejvýš pěti prvky. +more Tento vzor je tvaru vzor/;podminka, kde podminka je výraz, který musí vrátit True či False. Alternativou je použití testovací funkce. Předchozí vzor lze ekvivalentně přepsat do tvaru x_List. (Length[#], jenž je tvaru vzor. test, kde test je funkce, která po aplikování na vzor musí vrátit True či False. Podobně lze postupovat i když místo ryzí funkce použijeme funkci standardní. Například vzor a_. EvenQ označuje libovolný výraz, pro nějž funkce EvenQ vrátí True. Vzhledem k tomu, že EvenQ testuje, kde je vstupní parameter sudé číslo, označuje tento vzor tedy sudé číslo.
Vzory jsou podporovány mnoha funkcemi jako Switch při porovnávání jednotlivých případů se vstupní hodnotou, Cases pro výběr prvků ze seznamu, které splňují dodatečná kriteria atd.
Pravidla
WL umožňuje práci s nahrazovacími pravidly (angl. rules, popř. +more transformation rules), díky nimž lze nahradit část výrazu výrazem jiným. Máme-li například seznam tvaru {a, 2, a, 3}, který chceme změnit do tvaru {1, 2, 1, 3}, můžeme toto provést voláním.
{a, 2, a, 3} /. a->1 (* vrátí: {1, 2, 1, 3} *)
kde a->1 je pravidlo, které udává, že každý výskyt výrazu a se má nahradit číslem 1. Podobně jako v případě přiřazení, existuje i přímé a odložené pravidlo. +more Přímé pravidlo (Rule, zkráceně ->) vyhodnotí pravou stranu přiřazení ve chvíli, kdy je toto pravidlo definováno, zatímco odložené pravidlo (RuleDelayed, zkráceně :>) vyhodnotí pravou stranu až ve chvíli volání. Srovnej:.
{a, a, a} /. a->RandomReal[] (* vrátí: {0.209308, 0.2093080, 0.209308} *) {a, a, a} /. a:>RandomReal[] (* vrátí: {0.827961, 0.0109041, 0.161149} *)
Jak levá, tak pravá strana pravidla může mít velmi komplikovanou strukturu založenou na vzorech. Toto lze efektivně využít například ve chvíli, kdy nelze dopředu určit, čím se má daný výraz nahradit, protože jeho tvar závisí na tvaru nahrazované hodnoty. +more Srovnej následující kód:.
{x, 10, 3., 1, 2, -2} /. a_Integer?(#>1&):>ToString[a+1]" atd." (* vrátí: {x, "11 atd.", 3., 1, "3 atd.", -2} *)
Tento kód vyhledá v seznamu všechny výskyty celých čísel větších než jedna a nahradí je řetězcem, který obsahuje číslo o jedno větší s dodatkem " atd.".
Syntax vyraz /. a->b je ekvivalentní zápisu ReplaceAll[vyraz, a->b], což je dále ekvivalentní zápisu ReplaceAll[vyraz, Rule[a, b]]. +more Konstrukt a->b samotný žádné nahrazování neprovádí, jedná se pouze o recept, jak se má nahrazení provést. Samotné provedení má ale na starosti funkce ReplaceAll a jí příbuzné funkce jako ReplaceRepeated (zkráceně //. ).
Blokové struktury
Základními blokovými strukturami jsou ve WL konstrukty Block, Module a With, z nichž má každý trochu jinou funkcionalitu, jak popsáno níže.
Block
Block provádí dynamic scoping, kde se při provádění bloku dočasně přepíše hodnota dané proměnné. Syntaxe zní Block[{var1, var2, . +more, varN}, telo], kde var1 atd. jsou lokální proměnné a telo je blok kódu. Proměnné lze rovnou i inicializovat a psát Block[{var1 = hod1, var2 = hod2, . , varN = hodN}, telo], přičemž inicializovány nemusejí být všechny. Uvažme následující příklad:.
a = 42; Block[{a, b = 3, c}, a = b; Print["uvnitr Block: ", a, " ... ", c]; ]; Print[a];
Tento kód vypíše:
uvnitr Block: 3 ... c 42
Uvnitř Block můžeme přiřazovat do lokálních proměnných, viz příkaz a = b výše. Pokud nemá daná lokální proměnná přiřazenu hodnotu, je vrácena jako symbol, viz řádek "uvnitr Block: 3 . +more c" ve výpisu. Vzhledem ke způsobu lokalizace v Block není třeba, aby lokální proměnná byla explicitně zmíněna v těle, srovnej následující kód:.
b := a + 1 (* odložené přiřazení do proměnné b *) a = 2; (* globální hodnota proměnné a *) Block[{a = 5}, b] (* vrátí: 6 *) b (* vrátí: 3 *)
Module
Module provádí lexical scoping, kde jsou proměnné interně přejmenovávány tak, že mají unikátní název, přičemž jejich viditelnost není omezena na tělo bloku. Syntaxe je zcela analogická té pro Block. +more Pro srovnání s Block uvažme kód:.
a = 42; Module[{a, b = 3, c}, a = b; Print["uvnitr Module: ", a, " ... ", c]; ]; Print[a];
jenž vypíše:
uvnitr Module: 3 ... c$65048 42
Jak vidno, lokální proměnná c má pozměněné jméno. Tímto způsobem je možné, na rozdíl od Block, použít původně lokální proměnnou i po skončení bloku Module. +more Pro ilustraci uvažme následující kód, kde je v těle Module definována funkce f a tato je posléze vrácena:.
Module[{f}, f[x_] := x^2; f] (* vrátí: f$65834 *) f$65834[y] (* vrátí y^2 *)
Původně lokální proměnná f je přejmenována na f$65834 a jako takovou ji lze použít i vně Module.
With
With provádí lokalizaci konstant, to jest proměnných, jimž nelze po zbytek bloku měnit hodnotu. Nelze tak do takových proměnných přiřazovat, na rozdíl od Block a Module. +more Syntaxe je opět zcela analogická té pro Block s tím, že každou lokální proměnnou je nutno inicializovat, srovnej kód:.
a = 42; With[{a = 3}, Print["uvnitr With: ", a]; ]; Print[a];
jež vypíše:
uvnitr With: 3 42
Blok With je v mnoha ohledech spíše než bloku Block podobný substitučním funkcím jako ReplaceAll. Na rozdíl od nich substituce neprobíhá po vyhodnocení výrazu, ale před ním, srovnej:
f[x_] := If[x 2 (* vrátí: 2 *)
Na prvním řádku je definována funkce f, která vrátí buď "maly", je-li vstupní parametr menší než 1, anebo "velky", je-li parametr větší než 1. V případě, že vstupní parametr nemá přiřazenu žádnou hodnotu, vrátí funkce f tento parametr nevyhodnocený. +more Na druhém řádku je v bloku With do proměnné x přiřazena hodnota 2 a tato je posléze poslána do funkce f. Na třetím řádku je obdobná situace, kde se použije substituční pravidlo, kterým se parametr x nahradí hodnotou 2. Tato substituce ale na rozdíl od druhého řádku probíhá až po vyhodnocení funkce f, čímž pádem obdržíme jiný výsledek.
Strukturování kódu
Jmenné prostory
Každý symbol ve WL je součástí nějakého jmenného prostoru, kterým se ve WL říká kontexty (angl. contexts). +more Základním kontextem pro předdefinované symboly je System, výchozím kontextem pro uživatelem definované symboly je pak Global. Stejně pojmenované symboly ve dvou různých noteboocích či buňkách lze lokalizovat tím, že se jim přiřadí kontext jedinečný pro daný notebook či buňku. Definovat lze i vlastní kontexty. Symbol x s explicitně vypsaným kontextem mujkontext se udává kódem mujkontext`x, kde ` je zpětný apostrof. Kontexty lze i vnořovat a psát tak např. nadkontext`podkontext`x. Aktuální kontext je uložen v proměnné $Context, zjistit kontext daného symbolu lze funkcí Context. Funkce Contexts vrací seznam všech dostupných kontextů a proměnná $ContextPath obsahuje seznam kontextů, které jsou prohledávány při hledání definice pro zadaný symbol. Každý balík definuje nový kontext a při nahrání balíku funkcí Needs je tento kontext vložen do proměnné $Packages. Po nahrání balíku není nutné explicitně vypisovat u každého symbolu jeho kontext.
Vypsat všechny symboly v daném kontextu lze příkazem . jmenokontextu`*, kde jmenokontextu je jméno daného kontextu. +more Vypsat všechny symboly definované uživatelem v daném běhu jádra tak lze voláním . Global`*. Viz též oddíl #Nápověda|„Nápověda“.
Balíky
Balíky (angl. packages) jsou ucelené kusy kódu zabaleného do kontextu a uložené v samostatném souboru s příponou . +morewl. Kód balíku začíná výrazem BeginPackage a končí výrazem EndPackage. Funkce a proměnné, které jsou používány pouze uvnitř balíku a které nemají být přímo přístupny uživateli balíku, lze vložit mezi výrazy Begin a End. Typický balík má následující strukturu:.
BeginPackage["NovyKontext`"] (* počátek balíku a definice kontextu *)
novaFunkce::usage = "Dokumentační řetězec nové funkce."; (* tím, že funkci uvedeme před příkazem Begin, zajistíme, že je viditelná po načtení balíku uživateli *)
Begin["`Private`"] (* počátek části kódu, jež není přímo přístupná uživateli *)
novaFunkce[x_] := interniFunkce[x]^2 (* definice funkce *) interniFunkce[x_] := x + 1 (* tato funkce není viditelná uživateli *)
End[] (* konec interních definic *)
EndPackage[] (* konec balíku *)
Balík funkcí lze načíst buď pomocí funkce Get, jež vyhodnotí kód v balíku při každém volání této funkce, nebo funkcí Needs, která vyhodnotí kód balíku jen při prvním volání. Externí programy, jež dokážou komunikovat s jádrem protokolem WSTP, lze propojit s jádrem pomocí funkce Install. +more Dynamické knihovny lze nahrát přímo do výpočetního jádra voláním funkce LibraryLoad a příbuzných funkcí.
Paclety
Nadstavbou balíků jsou paclety (angl. paclets), což jsou v podstatě archivy, jež mohou obsahovat řadu balíků s kódem ve WL i jiných programovacích jazycích, dokumentaci, dynamické knihovny či stylopisy. +more Paclet se z obyčejného archivu stane tím, že se do archivu vloží soubor s názvem PacletInfo. wl, jež obsahuje výraz s hlavičkou PacletObject (do verze 12. 1 s hlavičkou Paclet), jež obsahuje metadata o souborech v archivu obsažených. Paclety nabízejí širší funkcionalitu než balíky a je nutné je do výpočetního systému nejdříve nainstalovat funkcí PacletInstall. Od verze 12. 1 lze paclety centrálně ukládat do online repozitáře.
Funkce
Základní použití
Funkce lze volat pomocí jednoduchých hranatých závorek, do nichž jsou vepsány vstupní parametry, např. : Sin[0. +more9], Table[i,{i,3}] či f[3] pro uživatelem definovanou funkci f. Základní tvar definice funkce jedné proměnné vypadá následovně:.
f[x_] := x^2
kde na levé straně je výraz tvaru jmenofunkce[vstup_] a na pravé straně odloženého přiřazení je tělo funkce zpracovávající vstup. Je-li potřeba při výpočtu použít dodatečné proměnné, lze tyto lokalizovat pomocí bloků Block, With či Module:
f[x_] := Module[{y}, (* lokální proměnná y *) y = x^2; y + 1 (* popř. Return[y + 1]; *) ]
Všimněme si, že není nutno použít příkaz Return, protože blok vrací automaticky hodnotu na posledním řádku.
Funkce jsou first-class objekty a tak lze s nimi nakládat stejně jako s proměnnými, srovnej:
fun = Cos; If[podm, fun = Sin]; fun[0.2]
Tento kód aplikuje na číslo 0,2 buď cosinus, anebo sinus v závislosti na pravdivostní hodnotě proměnné podm.
Definice
Přetěžování a polymorfizmus
Při definici funkce lze uplatnit širokou paletu vzorů, které specifikují, v jakých případech má být daná definice použita. Jedné funkci lze přiřadit vícero definic pro různé druhy vstupů a WL tak umožňuje přetěžování a polymorfizmus. +more Pokud danému vstupu nevyhovuje ani jedna definice, zůstává volaný výraz nevyhodnocen. Pokud naopak danému vstupu vyhovuje více definic, je použita ta, která je nejspecifičtější. Srovnej:.
f[x_] := x^2 (* funkce f jedné proměnné *) f[x_, y_] := x + y (* tatáž funkce, ale definována pro dva vstupní parametry *) f[x_, y_?EvenQ] := "sude cislo na vstupu" (* opět tatáž funkce, ale nyní je její akce definována pro případy, kdy je druhý vstup sudé číslo *)
Voláme-li tuto funkci f na různé vstupy, můžeme obdržet:
f[4] (* vrátí: 16 *) f[4, 2] (* vrátí: "sude cislo na vstupu" *) f[4, 3] (* vrátí: 7 *) f[4, 3, 7] (* vrátí: f[4, 3, 7] *)
Podporovány jsou i složitější vzory. Například následující funkce vypíše číslo 1 tehdy, kdy je první vstup kladný a druhý vstup je větší než ten první. +more Ve všech ostatních případech vypíše 0:.
f[x_?Positive, y_]/;(y > x) := 1 f[_, _] := 0
Vstupní a výchozí hodnoty
Vstupním parametrům lze zadávat výchozí hodnoty a to dvěma způsoby. Buď pomocí výrazu Default, anebo syntaxí používající dvojtečku v definici funkce:
Default[f] = 3; (* výchozí hodnota parametru funkce f je 3 *) f[x_.] := x + 1 (* aby byla použita výchozí hodnota, je nutno ke vzoru x_ připojit tečku *) g[x_ : 3] := x + 1 (* ekvivalentní definice pomocí dvojtečky *) f[] (* vrátí: 4 *) g[] (* vrátí: 4 *)
Lze navíc i omezit obor možných vstupních hodnot tím, že se specifikuje podmínka, kterou musí vstupní parametr splňovat. Například následujícím kódem lze definovat funkci h, která pro sudé číslo vrátí číslo o jedna menší, pro liché číslo zůstane nevyhodnocena a pokud není zadán žádný vstup, použije se automaticky hodnota vstupu rovná 2:
h[x : _?EvenQ : 2] := x - 1 (* h[vstup : podminka : vychoziHodnota] := atd. *) h[1] (* vrátí: h[1] *) h[2] (* vrátí: 1 *) h[] (* vrátí: 1 *)
Druhy přiřazení
Při definicích funkcí je nutné dbát rozdílu mezi přímým a odloženým přiřazením, viz sekci #Přiřazení|„Přiřazení“. Srovnej následující tři definice, kde jsme nejdříve do globální proměnné x uložili hodnotu 5:
f1[x] = x^2; (* bez vzoru a odloženého přiřazení *) f2[x_] = x^2; (* vzor a přímé přiřazení *) f3[x_] := x^2; (* vzor a odložené přiřazení *) {f1[y], f2[y], f3[y]} (* vrátí: {f1[y], 25, y^2} *)
V prvním řádku se při definici funkce f1 použije hodnota globální proměnné x, to jest 5, a první řádek tak odpovídá přiřazení f1[5] = 25. Funkce f1 tak má definovanou hodnotu jen pro jeden jediný vstup a tím je číslo 5. +more Ve druhém řádku je v hlavičce funkce použit vzor x_, na pravé straně přiřazení ale vystupuje opět globální proměnná, jež je umocněna na druhou. Druhý řádek tak odpovídá situaci, kde funkce f2 pro jakýkoliv vstup vrátí hodnotu 25. Třetí řádek používá jak vzor x_, tak odložené přiřazení, které propojí hodnotu vzoru na levé straně se symbolem x na straně pravé. Tato poslední definice se chová očekávaným způsobem.
Ačkoli je třeba obyčejně používat odložené přiřazení, jak plyne z předchozího odstavce, někdy je přeci jen výhodné použít přiřazení přímé. A to v případě, kdy je vhodné definovat hodnotu funkce pro konkrétní hodnoty vstupů. +more Chceme-li například ručně definovat funkci sinc, jež je pro nenulová x dána vztahem sinc(x) = sin(x)/x, přičemž pro nulové x dodefinovat sinc(0) = 1, lze toto učinit následujícím kódem:.
sinc[x_] := Sin[x]/x; sinc[0] = 1;
Výpočetní systém rozpozná, že definice na druhém řádku je specifičtější než ta na řádku prvním a při volání sinc[0] je tak aplikována jako první, čímž obdržíme správný výsledek 1. Alternativním způsobem k výše uvedené definici je použití funkce Piecewise:
sinc[x_] := Piecewise[, 1]
Memoizace
Někdy je výpočet hodnoty dané funkce na konkrétní vstup náročný a zdlouhavý. Pokud se tento výpočet v kódu opakuje, lze jeho výsledek dynamicky uložit jako součást definice dané funkce metodou zvanou memoizace. +more Mějme funkci f, jejíž definice zní f[x_] := (tělo funkce). Pokud místo tohoto zápisu užijeme zápisu:.
f[x_] := f[x] = (tělo funkce)
dojde při každém volání funkce k vyhodnocení jejího těla pro konkrétní vstup, třeba 32, a výsledek je uložen do výrazu f[32], který se tak stává součástí definice funkce f. Takto lze dynamicky během běhu kódu měnit definice funkcí i jiných objektů. +more Viz příklady „Fibonacciho posloupnost“ a „Faktoriál“ v článku Wolfram Language.
Třídy funkcí a uzávěry
Lze vytvářet i konstrukty s více než jen jednou hranatou závorkou, např. g[x_][y_] := y^x. +more Takto definovanou funkci lze chápat jako celou třídu funkcí, kde první vstup hraje roli parametru, jež rozlišuje mezi jednotlivými funkcemi dané třídy. Výraz g[2] není vyhodnocen až do chvíle, než je aplikován na nějaký vstup a lze ho chápat jako operátor druhé mocniny, protože f[2][x] vrátí x^2.
Podobně se chovají funkce implementované pomocí Module, které vracejí jako hodnotu jinou funkci. Je-li při definici vnitřní funkce použit vstupní parametr funkce vnější, je tento parametr držen v definici vnitřní funkce i po opuštění těla funkce vnější:
f[x_] := Module[{k}, (* uzávěr *) k[y_] := x + y; (* definuj lokálně funkci k *) k (* vrať funkci s uloženou hodnotou proměnné x *) ] g = f[3]; (* vrátí funkci, která ke vstupu přičítá 3 *) g[5] (* vrátí: 8 *)
Ryzí funkce
WL podporuje anonymní funkce, které nazývá ryzí funkce (angl. pure functions). +more Tyto funkce jsou reprezentovány jako výrazy s hlavičkou Function, běžně se ale zapisují následující notací:.
(výraz obsahující symbol #) &
Symbol # (neboli Slot) představuje vstupní parametr a ampersand na konci určuje, že se jedná o ryzí funkci. Pokud je vstupních parametrů více, lze každému slotu udělit číslo, viz například:
(#1 + #2) & (* součet dvou vstupů *)
Pokud není třeba přistupovat ke každému vstupu zvlášť, lze použít zápis ##n, který představuje všechny vstupy od n-tého počínaje. Pokud jsou vstupními parametry klíče asociativního pole, lze sloty pojmenovat:
asoc = "Alik", "vek"->15|>; (#jmeno "u")&[asoc] (* vrátí: "Aliku" *)
Ryzí funkci lze definovat i následujícím způsobem známým z matematiky:
x |-> (výraz obsahující symbol x)
kde místo slotů použijeme pojmenované parametry. Tato syntaxe definuje funkci. Chceme-li tuto pojmenovat pro pozdější použití, lze to učinit standardním přiřazením:
druhaMocnina = x |-> x^2; (* definice *) druhaMocnina[3] (* volání, vrátí: 9 *)
Aplikace
Pomocí zvláštní notace
Funkci lze na vstupní parametry aplikovat různými způsoby - buď pomocí speciálních funkcí jako Apply, jak je rozebráno níže, anebo pomocí odpovídající syntaxe, jak si ukážeme v následujícím. Notací pro aplikaci nějaké funkce f na vstupní parametry existuje několik, viz tabulku níže:
Normální notace | f[vstupy] | vstupní parametry v hranatých závorkách, před nimiž je napsáno jméno funkce | Mod[5, 2] (* vrátí: 1 *) |
---|---|---|---|
Prefixová notace | f@vstup | jméno funkce následované zavináčem a vstupním parametrem | Print@"Ahoj. +more" (* vypíše: Ahoj. *) |
Infixová notace | vstup1~f~vstup2 | první a druhý vstupní parametr jsou odděleny dvěma vlnovkami, mezi něž je vloženo jméno funkce | {a, b}~Join~{c} (* vrátí: {a, b, c} *) |
Postfixová notace | vstup//f | za vstupními parametry následuje dvojité lomítko a jméno funkce | {{1}, {2}}//Flatten (* vrátí: {1, 2} *) |
Pomocí funkcí vyšších řádů
Aplikaci libovolné funkce na vstupní parametry lze provést i pomocí funkce Apply:
Apply[f, {a, b, c}] (* vrátí: f[a, b, c] *) f @@ {a, b, c} (* ekvivalentní kompaktní zápis *)
Funkce Apply má širší okruh použití, kdy lze s pomocí jejího druhého parametru nastavit, jak se daná funkce aplikuje na vícero vstupních hodnot umístěných do seznamů či jiných výrazů:
Apply[f, {{1, 2}, {3, 4}}, {1}] (* vrátí: {f[1, 2], f[3, 4]} *) f @@@ {{1, 2}, {3, 4}} (* ekvivalentní kompaktní zápis *)
Podobně se chová funkce Map:
Map[f, {1, 2, 3, 4}] (* vrátí: {f[1], f[2], f[3], f[4]} *) f /@ {1, 2, 3, 4} (* ekvivalentní kompaktní zápis *)
Map[f, {{1, 2}, {3, 4}}, {2}] (* vrátí: {{f[1], f[2]}, {f[3], f[4]}} *) Map[f, {{1, 2}, {3, 4}}] (* vrátí: {f[{1, 2}], f[{3, 4}]} *)
Aplikaci několika funkcí lze i řetězit způsobem, který reflektuje matematické skládání funkcí. Výrazem Composition[f,g] či ekvivalentně f @* g je představována funkce, která na daný vstup x vrátí f[g[x]]. +more Je podporována i postfixová varianta RightComposition[f,g] či ekvivalentně f /* g, která na daný vstup x vrátí g[f[x]]. Srovnej tři řádky se stejnou funkcionalitou:.
f /@ (g /@ {1, 2, 3}) (* vrátí: {f[g[1]], f[g[2]], f[g[3]]} *) f[g[#]]& /@ {1, 2, 3} (* totéž s využitím ryzí funkce *) f @* g /@ {1, 2, 3} (* totéž s využitím skládání funkcí *)
WL nabízí řadu dalších funkcí, s jejichž pomocí lze programově aplikovat funkci na různě strukturované vstupy, viz např. funkce Nest a Fold v sekci #Cykly a jejich ekvivalenty|„Cykly a jejich ekvivalenty“. +more Dalšími funkcemi jsou např. Thread a MapThread s následující funkcionalitou:.
Thread[{a, b, c} -> {1, 2, 3}] (* vrátí: {a->1, b->2, c->3} *) MapThread[f, {{a, b, c}, {1, 2, 3}}] (* vrátí: {f[a, 1], f[b, 2], f[c, 3]} *)
Ve verzi 12. 2 byla zavedena funkce ApplyTo, která zobecňuje přiřazovací operátory typu *= na libovolný zadaný operátor. +more Předpokládejme, že do proměnné x je uložena hodnota h a na tuto proměnnou chceme aplikovat funkci f a výslednou hodnotu opět uložit do proměnné x. Toto lze provést kódem x = f[x], kde je nutno dvakrát vypsat jméno proměnné. Totéž lze provést i kódem ApplyTo[x, f] či ekvivalentně x //= f.
Volby
Chování funkce lze ovlivnit nejen vstupy, ale i volbami (angl. options), které připomínají pojmenované argumenty v Pythonu. +more Volby mají tvar přiřazovacích pravidel nazevVolby -> jejiHodnota, přičemž jejich název může být buď symbol nebo řetězec. Konkrétní hodnotu dané volby lze vepsat jako pravidlo při volání funkce do hranatých závorek spolu s ostatními argumenty. Například nadpis grafu vytvořeného funkcí Plot lze specifikovat volbou PlotLabel:.
Plot[Sin[x], {x, 0, Pi}, PlotLabel->"Graf funkce sinus"] (* nadpis grafu zní "Graf funkce sinus" *)
Hodnotu voleb lze změnit i funkcí SetOptions a to následovně:
SetOptions[Plot, PlotLabel->"Graf funkce sinus"]; Plot[Sin[x], {x, 0, Pi}] (* nadpis grafu zní "Graf funkce sinus" *)
Tento druhý způsob je vhodnější například ve chvílích, kdy je třeba měnit volbu u několikera volání téže funkce.
Volby lze dodat i do uživatelem definovaných funkcí. Nejprve je třeba výrazem Options určit, jaké volby má daná funkce podporovat. +more Do definice funkce je pak třeba vložit vzor OptionsPattern[]{{Poznámka|Do verze 6 se místo OptionsPattern[] používal vzor ve stylu opts___. OptionQ a místo OptionValue bylo nutno psát kód ve stylu volba /. {opts} /. Options[funkce]. }} a v těle funkce pak funkcí OptionValue získat hodnotu dané volby. Jednoduchá funkce pak může vypadat následovně:.
Options[f] = {"MojeVolba"->True}; (* definuj volby *) f[x_, OptionsPattern[]] := Module[{v}, (* do seznamu parametrů je vložen vzor OptionsPattern[] *) v = OptionValue["MojeVolba"]; (* do proměnné v vlož hodnotu volby "MojeVolba" *) If[v, x, x^2] ]; f[3, "MojeVolba"->False] (* volání funkce, vrátí: 9 *)
Atributy
Každá funkce ve WL se může vyznačovat i jedním či více atributy (angl. attributes), jež specifikují obecné chování funkce. +more Seznam všech atributů dané funkce f lze održet voláním Attributes[f]. Atribut nový lze nastavit funkcí SetAttributes a stávající atribut lze smazat funkcí ClearAttributes. Například funkce Sin, představující sinus, má ve verzi 13. 1. 0 atributy {Listable, NumericFunction, Protected}. Atribut Listable značí, že se má při aplikaci na seznam tato funkce aplikovat automaticky na každý člen seznamu zvlášť. Atribut NumericFunction říká, že funkce na číselné vstupy vrátí číselnou hodnotu a konečně atribut Protected značí, že funkci Sin nelze přímo předefinovat. Roli atributu Listable lze snadno ilustrovat na následujícím příkladu, kde je tento atribut přiřazen symbolu g:.
SetAttributes[g, Listable]; (* symbolu g je nastaven atribut Listable *) g[{1, 2, 3}] (* vrátí: {g[1], g[2], g[3]} *) ClearAttributes[g, Listable]; (* atribut Listable je smazán *) g[{1, 2, 3}] (* vrátí: g[{1, 2, 3}] *)
Všimněme si, že jsme výše ani žádnou definici symbolu g nepřiřadili. Uvedené chování je určeno čistě atributem.
Atributů existuje celá řada. Například atribut HoldAll říká, že se vstupní argumenty nemají před voláním funkce vyhodnotit. +more Standardně se například výraz f[1+1] nejprve vyhodnotí jako f[2] a teprve tehdy je volána funkce f. Pokud má f ale atribut HoldAll, je do f přímo zaslán výraz 1+1, jenž je interně interpretován jako Plus[1,1] a lze na něm provádět v těle funkce dodatečné operace.
Chybová a dokumentační hlášení
Pro danou funkci f lze specifikovat text chybových hlášení syntaxí f::jmeno = "text", kde jmeno je jméno chybové hlášky a "text" je její znění. Danou hlášku lze v těle funkce vyvolat funkcí Message. +more Srovnej.
f::nedelnulou = "Dělení nulou!"; f[x_, y_] := If[y == 0, Message[f::nedelnulou], x/y]
Při volání funkce f[x, 0] vypíše tato text "Dělení nulou!". Chybové hlášení může obsahovat i parametry, které se vkládají do řetězce stylem používaným funkcí StringForm:
f::spatnyvstup = "Špatný vstup: ``"; f[x_] := If[x != 0, Message[f::spatnyvstup, x], x]
Při volání f[32] vypíše funkce hlášení "Špatný vstup: 32".
Zvláštní postavení má hlášení s vyhrazeným názvem usage, které místo chybového hlášení představuje dokumentační řetězec, který se vypíše při vyvolání nápovědy pro danou funkci:
f::usage = "Zbytečná funkce"; f[x_] := 1 ?f (* vypíše "Zbytečná funkce" *)
Pokročilé definice
Při volání funkce může dát editor uživateli na srozuměnou, zda je do volání třeba doplnit parametry. Například v případě, kdy uživatel napíše do volání funkce parametry dva a je přitom povolen jen jeden, je druhý parametr zvýrazněn červeně. +more Informaci tohoto rázu lze k definované funkci přiřadit pomocí výrazu SyntaxInformation. V sekci „Pokročilá definice funkce“ článku Wolfram Language lze nalézt příklad definice funkce využívající tuto a další pokročilé možnosti probrané výše.
Ve WL jsou funkce interně reprezentovány jako nahrazovací pravidla v seznamech, které lze vyvolat funkcemi UpValues, DownValues, OwnValues či SubValues. Tyto funkce lze aplikovat na kterýkoliv symbol ve WL, ne jen na funkce. +more Seznam vrácený funkcí OwnValues obsahuje pravidla vyplývající z přiřazení nějaké hodnoty danému symbolu:.
a = 3; OwnValues[a] (* vrátí: {HoldPattern[a]:>3} *)
kde hlavička HoldPattern zajišťuje, že se výraz a automaticky nevyhodnotí na hodnotu 3. Podobně seznam DownValues obsahuje pravidla, jež vyplývají z přiřazení ve tvaru f[var_] := telo typické pro funkce:
f[x_] := x^2 DownValues[f] (* vrátí: {HoldPattern[f[x_]]:>x^2 *)
Funkce lze ale definovat i se dvěma a více posloupnostmi argumentů, kde je každý uzavřen mezi hranaté závorky. Takováto přiřazení jsou uchovávána v seznamu vyvolaným funkcí Subvalues:
f[x_][y_] := x^y SubValues[f] (* vrátí: {HoldPattern[f[x_][y_]]:>x^y *)
Tím se dostáváme k poslednímu seznamu přiřazení spravovaného funkcí UpValues. Tato přiřazení odpovídají definicím, kdy namísto specifikování toho, jak má daná funkce působit na vstupní hodnoty, určíme pro konkrétní hodnotu, jak na ní má působit daná funkce. +more Uvažme situaci, kdy definujeme novou symbolickou konstantu konst a chceme, aby funkce sinus měla pro tuto konstatu hodnotu 0,2, to jest Sin[konst] = 0. 2, aniž bychom třeba konstantě samotné přiřadili jakoukoli hodnotu. Buď můžeme zasáhnout do definice předdefinované funkce Sin a uměle do ní vložit přiřazení Sin[konst] = 0. 2, anebo můžeme toto přiřazení vložit do definice konstanty konst, čímž nedojde k jakékoliv manipulaci s definicí funkce Sin. Tento druhý způsob odpovídá přiřazení ve smyslu UpValues. Tato přiřazení mají speciální syntaxi, kde rozdíly mezi všemi čtyřmi způsoby níže leží za rámcem tohoto článku:.
a/:f[a] = hod (* definice pomocí TagSet *) a/:f[a] := hod (* definice pomocí TagSetDelayed *) f[a] ^= hod (* definice pomocí UpSet *) f[a] ^:= hod (* definice pomocí UpSetDelayed *)
Výše uvedený příklad by tak šlo definovat způsobem konst/:Sin[konst] = 0.2.
Ostatní
V následujícím je neúplný výčet některých dalších sad funkcí seskupených podle jejich funkcionality.
Externí soubory
Data lze získat funkcí Import, exportovat pak funkcí Export. Uložit definici nějaké proměnné, funkce či datové struktury lze funkcí Save, jež vytvoří externí textový soubor, nebo funkcí DumpSave, jež vytvoří externí binární soubor. +more Získat kód z externího souboru lze funkcí Get (zkráceně ), uložit data či kód do externího souboru lze funkcí Put (>>) či PutAppend (>>>), která původní obsah nepřepisuje a jen přidává další obsah na konec souboru.
data = Import["staradata.txt"]; (* importuj data ze souboru "staradata.txt" *) data >> "novadata.txt" (* zapiš hodnotu proměnné data do souboru "novadata.txt" *)
Úprava výrazů
Podporováno je mnoho funkcí pro algebraické a další úpravy symbolických výrazů. Zjednodušit daný výraz lze funkcí Simplify, která aplikuje na vstupní výraz různá transformační pravidla ve snaze tento výraz zjednodušit. +more Větším počtem transformačních pravidel disponuje příbuzná funkce FullSimplify. Je-li důležité při zjednodušení uvést i všechny podmínky, za kterých lze vstupní výraz zjednodušit, je vhodnější použít funkci Reduce. Řešení rovnic a jejich soustav lze funkcí Solve, logické výrazy lze zjednodušovat pomocí funkce Resolve apod.
Simplify[Sin[x]^2 + Cos[x]^2] (* vrátí: 1 *) Solve[x^2 + 3x + 2
0] (* vrátí: {{x->-2}, {x->-1}} *) Reduce[x^2 + 3x + 2
0] (* vrátí: x
-2 || x
-1 *)
Regulární výrazy
WL umožňuje zadávat regulární výrazy dvěma způsoby. Buď lze do funkce RegularExpression vepsat řetězec ve stylu jazyka Perl, který odpovídá danému regulárnímu výrazu, anebo lze použít řetězcové vzory (angl. +more string patterns), které jsou řetězcovou obdobou WL vzorů. Řetězcové vzory jsou výrazy s hlavičkou StringExpression, které mají syntaxi velmi podobnou vzorům s hlavním rozdílem, že jednotlivé části vzoru jsou pospojovány dvojitými vlnovkami ~~ a jsou podporovány primitivy specifické pro řetězce. Například vzor "t"~~_~~"k" představuje řetězce o třech znacích, jejichž první znak je "t" a poslední znak je "k". Takovému vzoru vyhovují například slova tak, tik, tok, tuk.
StringMatchQ["tak", "t"~~_~~"k"] (* vrátí: True *) StringMatchQ["taak", "t"~~_~~"k"] (* vrátí: False *)
Paralelizované výpočty
Paralelizace je umožněna funkcemi jako Parallelize, ParallelTable či ParallelDo. Tímto způsobem lze buď distribuovat výpočet mezi několik výpočetních jader na jednom počítači, anebo lze výpočet poslat do výpočetních clusterů. +more Výpočetní jádra se nastartují a inicializují automaticky při prvním volání funkce jako ParallelTable. Totéž lze ale udělat i manuálně funkcemi LaunchKernels a DistributeDefinitions. Od verze 12. 2 lze odeslat kód do vzdáleného WL výpočetního jádra pomocí funkce RemoteEvaluate či nechat výpočet provádět na vzdálených serverech spravovaných třetími stranami pomocí funkcí jako RemoteBatchSubmit.
Grafika
WL dovoluje vytvářet dvourozměrnou rastrovou (výraz Image) i vektorovou (výraz Graphics) grafiku a jejich trojrozměrné obdoby (Image3D a Graphics3D). Je podporována sada grafických primitiv, s nimiž lze programově vytvářet vektorovou grafiku. +more Pro dvourozměrnou vektorovou grafiku lze tuto kreslit přímo v editoru i manuálně, přičemž od verze 12. 2 je tato funkcionalita zabalena do prostředí Canvas. Spolu s tím lze vykreslovat grafy funkcí jak ve dvou tak třech rozměrech. Základními funkcemi jsou Plot pro vykreslení grafu reálné funkce jedné proměnné a Plot3D pro vykreslení reálné funkce dvou proměnných.
Plot[Sin[x], {x, 0, 2 Pi}] (* vykreslí sinusoidu v intervalu [0, Pi] *) Graphics[{Blue, Rectangle[{0, 0}, {2, 1}]}] (* vykreslí modrý obdélník mezi body {0, 0} a {2, 1} *)
Dynamické výrazy
WL podporuje tvorbu dynamicky se měnících výrazů, čímž lze přímo v editoru vytvářet interaktivní grafická uživatelská prostředí. Vysokoúrovňovou funkcí pro tvorbu interaktivního prostředí je Manipulate, jejímž prvním parametrem je kód, jenž se má dynamicky obměňovat, a další parametry jsou vstupní dynamické proměnné. +more Pro ilustraci je níže uveden kód, který vytvoří uživatelské prostředí, v němž je vykreslována sinusoida v mezích, které jsou dynamicky nastavovány uživatelem:.
Manipulate[Plot[Sin[x], {x, min, max}], {min, Pi, 2 Pi}, {max, Pi, 2 Pi}] (* vytvoří interaktivní prostředí, kde může uživatel nastavit hodnoty parametrů min a max *) (* při každé změně parametru se dynamicky zavolá příkaz Plot a automaticky se překreslí graf sinusoidy *)
Nízkoúrovňovější variantou, disponující dodatečnou funkčností, je využití hlavičky Dynamic, kterou lze obalit výraz, jenž se má dynamicky vyhodnocovat. Jako příklad uveďme následující kód:
Slider[Dynamic[x]] (* vytvoří vodorovný posuvník *) Dynamic[x] (* zobrazí aktuální polohu posuvníku *)
který zobrazí v editoru vodorovný posuvník, který lze myší posouvat, a aktuální poloha posuvníku je zobrazena jako reálné číslo pod posuvníkem. Dynamické struktury lze vnořovat a vytvářet komplexní uživatelská prostředí, často však výměnou za zvýšené výpočetní nároky a pomalejší odezvu. +more Hodnoty dynamických proměnných lze lokalizovat pomocí DynamicModule, čímž lze vytvářet obecnější struktury, než které jsou dostupné skrze Manipulate.
Systém udržuje interně seznam všech výrazů, které se mají dynamicky měnit, a aktualizuje jen ty, které jsou v daném okamžiku explicitně viditelné uživateli na obrazovce. Jinak je vyhodnocování pozastaveno. +more Aktualizace některých výrazů je prováděna přímo front endem bez nutnosti zatěžovat výpočetní jádro. Obecně komunikuje front end s jádrem třemi kanály - první kanál slouží ke standardnímu vyhodnocování příkazů, druhým kanálem posílá jádro požadavky front endu a kanál třetí, preemptivní, pak slouží k synchronnímu vyhodnocování dynamických výrazů. Takto lze současně provádět výpočty a interagovat s prostředím, aniž by čekání na uživatele znemožňovalo standardní vyhodnocování příkazů z front endu. Při větší zátěži však vyhodnocování výrazů z preemptivního kanálu může zablokovat front end.
Odkazy
Poznámky
Reference
Související články
Wolfram Language * Mathematica * Srovnání Pythonu a Wolfram Language * Funkcionální programování * Symbolické programování
Kategorie:Matematický software Kategorie:Počítačová algebra Kategorie:Funkcionální jazyky