Hlavní navigace

Úvod do jazyka Reason: proměnné a funkce

Radek Miček

Základními stavebními kameny programů v Reasonu jsou proměnné a funkce. Proto náš úvod do jazyka začneme právě jimi. Dále zodpovíme otázku, zda stačí, když programovací jazyk podporuje pouze funkce s jedním parametrem.

Doba čtení: 4 minuty

Definice proměnných a funkcí

prvním díle našeho seriálu jsme vygenerovali kostru jednoduché aplikace v Reasonu a nainstalovali plugin pro Reason do Visual Studia Code. Dnes začneme v Reasonu programovat. Otevřeme soubor src/page.re. Kromě zvýrazňování syntaxe nám Visual Studio Code ukazuje i typy některých proměnných.

Typy se zobrazují nad řádkem, kde je proměnná deklarována. Například proměnná handleClick má typ ('a, 'b) => unit (přesný význam tohoto typu vysvětlíme později).

Zadefinujme novou proměnnou crowns. Jak to provést? Pod řádek s definicí proměnné component (řádek začínající let component) vložme následující:

let crowns = 200;

Právě jsme zadefinovali naši první proměnnou! Její název je crowns, její typ je int a její hodnota je 200. Na rozdíl od mnoha populárních jazyků nejde v Reasonu do proměnné přiřadit jiná hodnota.

Zkusme zadefinovat druhou proměnnou. Pod řádek crowns přidejme

let crownsForOneDollar = 25.4;

Proměnná crownsForOneDollar má typ float. Nyní můžeme spočítat:

let dollars =  float_of_int(crowns) /. crownsForOneDollar;

Všimněme si dvou věcí:

  • Za lomítkem je tečka. Operátor /. přijímá dva float y a vrací float. Zatímco / (bez tečky) přijímá dva int y a vrací  int.
  • Reason neprovádí žádné implicitní konverze. Je tedy třeba ručně převést int na  float.

Oboje pomáhá typové inferenci. Navíc absence implicitních konverzí dělá kód jednodušším na pochopení.

float_of_int je funkce ze standardní knihovny stejně jako /.. Vlastní funkci vytvoříme pomocí  let:

let crownsToForeignCurrency = (crownsPerUnit, crowns) =>
   float_of_int(crowns) /. crownsPerUnit;

Funkce se jmenuje crownsToForeignCurrency. Nalevo od => v našem kódu je seznam parametrů funkce. Napravo od => je tělo funkce. Typ funkce je (float, int) => float. Nalevo od => jsou typy parametrů, napravo od => je typ návratové hodnoty.

Příklad použití:

let dollars2 = crownsToForeignCurrency(crownsForOneDollar, crowns);

Jiný příklad použití:

let crownsToDollars = crownsToForeignCurrency(crownsForOneDollar);

Výsledkem tohoto volání je funkce typu (int) => float, jenž převádí koruny na dolary. Co se stalo? Funkce crownsToForeignCurrency potřebuje dva argumenty, když predáme pouze jeden, není to chyba, vznikne funkce, která bude čekat na ten druhý.

Obecně, když máme funkci s n parametry a předáme jí jeden argument, dostaneme funkci, která čeká na zbývajících n – 1 argumentů. Můžeme tedy psát

let dollars3 = crownsToDollars(crowns);

Každá funkce v Reasonu má právě jeden parametr

Ve skutečnosti v Reasonu mají všechny funkce právě jeden parametr. Funkce se třemi parametry a, b, c je ve skutečnosti funkce s jedním parametrem a, která vrací funkci s jedním parametrem b, která vrací funkci s jedním parametrem c a tato poslední funkce počítá návratovou hodnotu poté, co dostane argument pro svůj jediný parametr  c.

Tudíž zápis

let f = (a, b, c) => Js.log(a ++ b ++ c);

je pouze zkratkou za

let f = (a) => (b) => (c) => Js.log(a ++ b ++ c);

Funkce g, g2 a g3 dělají totéž:

let g = f("Acko");
let g2 = (b) => (c) => Js.log("Acko" ++ b ++ c);
let g3 = (b, c) => Js.log("Acko" ++ b ++ c);

Typy se chovají podobně. Existuje řada možností, jak zapsat typ funkce  f:

(string, string, string) => unit
(string) => (string) => (string) => unit
(string) => (string, string) => unit
(string, string) => (string) => unit
(string) => ((string) => (string) => unit)

Typ unit značí, že návratová hodnota funkce není zajímavá (funkci f voláme kvůli výpisu do konzole prohlížeče, nikoliv proto, že chceme spočítat návratovou hodnotu).

Rovněž volání funkce lze provést několika způsoby:

f("a", "b", "c");
f("a")("b", "c");
f("a", "b")("c");
f("a")("b")("c");

Pojmenované argumenty

Nepříjemné je, že z volání funkce crownsToForeignCurrency nejde na první pohled poznat, co je kurz a co počet korun:

let dollars4 = crownsToForeignCurrency(25.4, 200);

Tuto vadu odstraníme tak, že definicí funkce vynutíme pojmenování jednoho z argumentů pomocí vlnky:

let crownsToForeignCurrency2 = (~crownsPerUnit, crowns) =>
   float_of_int(crowns) /. crownsPerUnit;

Změna se projeví i v typu funkce. Díky pojmenovanému argumentu je volání funkce srozumitelnější:

NMI18_Materna

let dollars5 = crownsToForeignCurrency2(~crownsPerUnit=25.4, 200);

Zobrazení výsledku ve stránce

Nyní je na čase prezentovat výsledek našeho výpočtu ve webové stránce. Využijeme k tomu Reactí komponentu Page, kterou vytváří funkce make. make vrací popis komponenty. Funguje tak, že vezme existující popis komponenty, jenž je uložen v proměnné component, udělá jeho kopii a v této kopii změní pole render. V poli render je funkce, která určuje, jak se komponenta vykreslí.

Abychom prezentovali výsledky našeho převodu korun na dolary, upravíme právě funkci v  render:

let make = (~message, _children) => {
  ...component,
  render: (self) =>
    <div onClick=(self.handle(handleClick))>
      (ReasonReact.stringToElement(message))
      (ReasonReact.stringToElement({j|BTW $crowns CZK is equal to $dollars5 USD!|j}))
    </div>
};

Syntax {j|řetězec|j} vytváří řetězec. Na rozdíl od řetězců uzavřených mezi dvojité uvozovky můžeme do těchto řetězců substituovat obsah proměnných a používat Unicode.

Závěr

V příštím díle dokončíme aplikaci převodník měn. Při tom se naučíme o záznamech v Reasonu, podíváme se na stavové komponenty v Reactu a také na to, jak v Reactu zpracovávat události z komponent.

Našli jste v článku chybu?