Blog | Partial application a currying LiveScriptu

Partial application a currying LiveScriptu

Jedna z velkých výhod LiveScriptu oproti Coffee nebo JavaScriptu, je partial application a currying zabudovaný do jazyka.

Co to znamená?

Každá funkce v LiveScriptu je, dá se říct, kus dat. A dá se s ní pracovat (zde konkrétně zjistit počet parametrů) jako s daty.

Takže můžu napsat:

plus = (+)

plus(1, 2) # 3

Funkce + očekává dva parametry.

Jenže já můžu v LiveScriptu zavolat funkci s méně parametry a ono to vygeneruje úplně novou funkci, která předané parametry při zadávání pošle dál.

Pokud vygeneruju funkci, která má přesně o 1 parametr méně než předchozí, jedná se o partial application:

plus2 = (+ 2)  # 4
plus2(2) # 4

No a protože nemusím psát závorky u argumentů, mohl bych napsat

plus2 2 # 4

Nebo

plus 2 2 # 4

A dokonce můžu napsat (což už je currying, tedy převod funkce fn(a, b, c) do podoby fn(a)(b)(c ), zde +(a)(b)

(+) 2 2 # 4

Je určitě pravda, že něco takového člověk nepoužívá každý den (ok, ok, někteří z vás možná jo).

Další věc je, že to umožňuje dělat naprostá zvěrstva (v dobrém slova smyslu).

Mám záznamy jmen a příjmení a chci je spojit.

var users = [{firstName: "John", secondName: "Doe"},
        {firstName: "Ivana", secondName: "Lendlova"},
        {firstName: "Petr", secondName: "Novak"}];

function spojJmena(user) {
        var out = [];
        for (key in users) {
                out.push( users[key].firstName + " " + users[key].lastName);
        }
        return out;
}

V LiveScriptu s Prelude.ls:

users =
        * firstName: "John", secondName: "Doe"
        * firstName: "Ivana", secondName: "Lendlova"
        * firstName: "Petr", secondName: "Novak"
map = require("prelude-ls").map

spoj-jmeno = -> "#{it.firstName} #{it.secondName}"
spoj-jmena = map spoj-jmeno
spoj-jmena users

Nebo na validaci:

filled = (val) -> val isnt '' and val isnt false and val isnt null
min-length = (arg, val) --> val.length >= arg
max-length = (arg, val) --> val.length <= arg
contains-number = (val) --> /[0-9]+/.test val

# bezny postup, ktery bych sam nejspis uprednostnil
validate-password = (val) -> filled(val) and min-length(5, val) and max-length(10, val) and contains-number(val)

# nebo s pomoci partial application:
and-list = require("prelude-ls").and-list
validate-password = (val) -> and-list [filled val, min-length 5 val, max-length 10 val, contains-number val]
# nebo
validate-password = (val) -> and-list map (->it val), [filled, min-length(5), max-length(10), contains-number]
# nevyhoda samozrejme je, ze ikdyz nebude hodnota vyplnena,
# budou se funkce aplikovat na vsechny prvky i tak

Jak můžete vidět, někdy vede partial application ke kratšímu kódu. Přiznám se, že ve funkcionálním programování toho zatím víc neumím než umím. Ale na otázku, zda je v těchto končinách něco, co mi může zkrátit kód a udělat mě produktivnějším, odpovídám ano!

Programování

Předejte zkušenosti i dalším a sdílejte tento článek!



Jiří Knesl
Business & IT konzultant

Jiří Knesl poprvé začal programovat v roce 1993. Od té doby, díky skvělým učitelům a později zákazníkům, měl možnost neustále růst v oboru vývoje webových aplikací a informačních systémů. v roce 2002 se přidal zájem o ekonomii a v roce 2006 o organizaci práce. Vším tím se konstantně profesně zabývá jak ve svém podnikání, tak i u zákazníků. Za posledních 5 let vydal na tato témata přes 400 článků.

Prohlédněte si moje reference

Mám zkušenosti z rozsáhlých projektů pro korporace, velké podniky, střední i malé firmy, ale i pro startupy v cloudu. Zvyšoval jsem jejich know-how, pomáhal nastavovat jejich organizační strukturu, byl lektorem a mentorem v náročných situacích. Podívejte se, jak vidí můj přínos samotní klienti.

Sledujte mé postřehy na sociálních sítích