Hlavní navigace

Funkce v programovacím jazyku R

21. 1. 2021
Doba čtení: 30 minut

Sdílet

 Autor: R Core Team
Funkce jsou jednou z nejužitečnějších abstrakcí používaných při vývoji. Jazyk R práci s funkcemi samozřejmě podporuje a funkce jsou zde dokonce plnohodnotným typem s podporou lexikálních uzávěrů i funkcí vyššího řádu.

Obsah

1. Funkce v programovacím jazyku R

2. Funkce bez návratové hodnoty, speciální nehodnota NULL

3. Návratová hodnota funkce, konstrukce return

4. Pojmenované parametry volaných funkcí

5. Nepovinné parametry s výchozí hodnotou

6. Anonymní funkce

7. Zavolání funkce pro všechny prvky seznamů nebo vektorů

8. Kombinace anonymní funkce a funkcí vyššího řádu sapply či lapply

9. Prostředí (environment)

10. Přístup k nelokálním proměnným

11. Lexikální uzávěry

12. Klasický příklad uzávěru – čítač (generátor sekvence)

13. Čítač s předem nastaveným krokem

14. Rekurzivní funkce

15. Funkce vyššího řádu v programovacím jazyce R

16. Funkce Reduce

17. Redukce zprava

18. Balíčky s alternativní formou definice funkcí

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Funkce v programovacím jazyku R

Jak jsme si již řekli v perexu článku, představují funkce v oblasti syntaxe a sémantiky programovacích jazyků jednu z nejužitečnějších abstrakcí vůbec. Pokud nějaký jazyk podporuje funkce (ideálně jako plnohodnotný datový typ), je možné programy strukturovat, izolovat čistě výpočetní části od částí, které mění stav aplikace atd. Některé programovací jazyky navíc díky podpoře lexikálních uzávěrů (closure) umožňují tvorbu generátorů atd. V programovacím jazyku R jsou funkce plnohodnotným datovým typem, což mj. znamená možnost využití funkcí vyšších řádů (higher order functions). Funkce navíc mohou modifikovat proměnné, které se nachází mimo oblast viditelnosti funkce, což se nejvíce využije právě při práci s uzávěry (pro modifikaci těchto proměnných se používá speciální operátor a nikoli například obdoba global či nonlocal z Pythonu).

Konstrukce funkcí je pochopitelně popsána přímo ve vestavěné nápovědě programovacího jazyka R:

help("function")
 
function                 package:base                  R Documentation
 
Function Definition
 
Description:
 
     These functions provide the base mechanisms for defining new
     functions in the R language.
 
Usage:
 
     function( arglist ) expr
     return(value)
      
Arguments:
 
 arglist: Empty or one or more name or name=expression terms.
 
    expr: An expression.
 
   value: An expression.

2. Funkce bez návratové hodnoty, speciální nehodnota NULL

Nejjednodušší funkcí vůbec (a asi i nejméně užitečnou funkcí) je funkce, která neakceptuje žádné parametry, nevrací žádnou hodnotu a má prázdné tělo. Takovou funkci je možné v programovacím jazyku R zapsat následujícím způsobem:

f0 <- function() {
}
Poznámka: ve skutečnosti lze zápis provést na jediném řádku, tj. uzavírací složená závorka nemusí být umístěna samostatně.

Pokud tuto funkci zavoláme, vrátí se speciální nehodnota NULL:

> f0()
 
NULL

Ve skutečnosti jsme NULL ještě nikdy v jazyku R nepoužili. Známe pouze speciální hodnoty NA a NaN (což jsou skutečné hodnoty se specifickým významem). NULL je ovšem poněkud odlišná v tom, že se skutečně jedná o „nic“, což se projeví například i při provádění relačních operací později v této kapitole. Pochopitelně se můžeme podívat do nápovědy:

> help(NULL)

Popis:

NULL                   package:base                    R Documentation
 
The Null Object
 
Description:
 
     ‘NULL’ represents the null object in R: it is a reserved word.
     ‘NULL’ is often returned by expressions and functions whose value
     is undefined.
 
Usage:
 
     NULL
     as.null(x, ...)
     is.null(x)
 
Arguments:
 
       x: an object to be tested or coerced.
 
     ...: ignored.

Lepší ovšem bude si způsoby práce s NULL vyzkoušet sami. Nejprve predikát is.null:

x <- NULL
 
is.null(x)
TRUE

Některé další predikáty vrací pro NULL hodnotu FALSE, takže se zdánlivě NULL příliš neliší od již zmíněných NA či NaN:

> is.numeric(x)
[1] FALSE

Ve skutečnosti tomu tak však vždy není. Relační operátory, které by měly vracet TRUE či FALSE totiž pro NULL na vstupu vrátí prázdný vektor typu logical:

> x == 1
logical(0)
 
> x == x
logical(0)
 
> x != x
logical(0)
 
> x < x
logical(0)
 
> x > x
logical(0)

V praxi tedy prakticky vždy, když očekáváme, že by mohla nějaká proměnná obsahovat NULL, musíme použít predikát is.null a nikoli například x != NULL.

3. Návratová hodnota funkce, konstrukce return

Z funkce se automaticky vrací hodnota posledního výrazu. To například znamená, že funkce vracející konstantu může vypadat následovně:

f1 <- function() {
    42
}

Otestujeme si chování takové funkce. Pokud si necháme vyhodnotit jen vlastní proměnnou s funkcí, vrátí se její zdrojový kód (což je docela užitečné):

> f1
 
function() {
    42
}

Pokud funkci budeme chtít zavolat, je nutné použít kulaté závorky, i když se jedná o funkci bez parametrů:

> f1()
 
[1] 42
Poznámka: výsledkem je skutečně hodnota 42.

Podobným způsobem můžeme vytvořit funkci se dvěma parametry, která vrací součet těchto parametrů:

add <- function(x, y) {
    x+y
}

Otestování na dvou celých číslech:

> add(1,2)
 
[1] 3

Parametry nemají uvedeny typ, takže můžeme použít například i komplexní čísla:

> add(1+2i, 3+4i)
 
[1] 4+6i

Ovšem například pro řetězce dojde k chybě, neboť pro ně není operátor + definován:

> add("a","b")
 
Error in x + y : non-numeric argument to binary operator

Pokud vám automatické vrácení hodnoty posledního výrazu nevyhovuje, je možné použít i konstrukci return, podobně, jako je tomu v mnoha dalších programovacích jazycích:

help(return)

Ovšem je nutné si dát pozor na to, že v R je nutné psát výraz (jehož hodnota se má vrátit) do závorek:

f1 <- function() {
    return 42
}

Předchozí kód je napsán chybně:

Error: unexpected numeric constant in:

Korektní zápis konstrukce return vypadá takto:

f1 <- function() {
    return(42)
}
 
f1()
 
42

Podívejme se nyní na složitější příklad, v němž je ve funkci použita minule popsaná rozhodovací konstrukce if-else:

classify.number <- function(x) {
  if (x > 0) {
    result <- "Positive"
  }
  else if (x < 0) {
    result <- "Negative"
  }
  else {
    result <- "Zero"
  }
  return(result)
}

Tato funkce vrací hodnoty podle očekávání:

> classify.number(-100)
[1] "Negative"
 
> classify.number(0)
[1] "Zero"
 
> classify.number(100)
[1] "Positive"

Konstrukce return se ovšem nemusí nacházet pouze na konci funkce, což si ukážeme na upravené verzi funkce classify.number:

classify.number <- function(x) {
  if (x > 0) {
    return("Positive")
  }
  else if (x < 0) {
    return("Negative")
  }
  else {
    return("Zero")
  }
}

Výsledky budou stejné, jako v předchozí funkci:

> classify.number(-100)
[1] "Negative"
 
> classify.number(0)
[1] "Zero"
 
> classify.number(100)
[1] "Positive"

4. Pojmenované parametry volaných funkcí

Připomeňme si ještě jednou funkci pro součet dvou čísel:

add <- function(x, y) {
    x+y
}

Při volání této funkce můžeme (pochopitelně) předávat poziční parametry::

> add(10, 20)
 
[1] 30

Parametry je ovšem možné při volání pojmenovat:

> add(x=10, y=20)
 
[1] 30

Což nám umožňuje nedodržet pořadí parametrů:

> add(y=20, x=100)
 
[1] 120

Umožněna je i libovolná kombinace pozičních a pojmenovaných parametrů, přičemž jsou poziční parametry postupně dosazovány tak, aby vyplnily místa neobsazená pojmenovanými parametry:

> add(x=100, 0)
 
[1] 100

I tento zápis je v jazyku R zcela korektní:

> add(y=100, 0)
 
[1] 100

5. Nepovinné parametry s výchozí hodnotou

V definici funkce u některých parametrů (nebo i všech parametrů) můžeme specifikovat výchozí (default) hodnotu:

pow <- function(x, y=2) {
    result <- x ^ y
    return(result)
}

Alternativní (kratší) způsob zápisu této funkce:

pow <- function(x, y=2) {
    x^y
}

Takovou funkci je možné volat s oběma pozičními parametry:

> pow(2,2)
[1] 4

Výchozí parametr je možné vynechat:

> pow(2)
[1] 4

Opět vynechání výchozího parametru, ovšem první parametr je pojmenován:

> pow(x=3)
[1] 9

Kombinace obou předchozích způsobů (pojmenování parametrů atd.):

> pow(y=3, 3)
[1] 27
 
> pow(y=10, x=2)
[1] 1024
Poznámka: s výchozími parametry se v jazyku R setkáme velmi často, zejména u funkcí ze standardní knihovny.

6. Anonymní funkce

Kromě běžných (pojmenovaných) funkcí popsaných v předchozích kapitolách je možné v programovacím jazyce R, podobně jako v mnoha dalších jazycích umožňujících funkcionální programování, vytvářet a používat takzvané funkce anonymní. Tyto funkce, které je možné s výhodou využít například při zápisu iterací nad prvky seznamů či při omezování oblasti platnosti proměnných, se vytváří opět s využitím konstrukce function (v jiných programovacích jazycích se ovšem setkáme s konstrukcí lambda, jejíž název je odvozen ze slavné Churchovy teorie Lambda kalkulu, která má poměrně velký význam jak v teoretické informatice, tak i v dalších odvětvích informatiky.

Samotný zápis anonymní funkce se příliš neliší od zápisu funkce pojmenované, pouze se funkce nepřiřazuje do proměnné, ale například se přímo volá tak, jako je tomu v následujícím jednoduchém demonstračním příkladu:

> (function(x) x*x)(5)
 
[1] 25

Povšimněte si toho, že samotný zápis funkce je umístěn do kulatých závorek, což je nutné z hlediska syntaxe – anonymní funkci voláme s nějakým parametrem umístěným za její definicí.

Poznámka: s anonymními funkcemi se v praxi setkáme i při použití funkcí vyššího řádu (higher order functions), o nichž se podrobněji zmíníme v patnácté kapitole.

7. Zavolání funkce pro všechny prvky seznamů nebo vektorů

Velmi často se setkáme s požadavkem na aplikaci (zavolání) nějaké funkce postupně pro všechny prvky vektoru nebo seznamu s tím, že výsledkem bude nový vektor nebo seznam. Pro tento účel existuje v programovacím jazyku R dvojice funkcí vyššího řádu nazvaných sapply a lapply:

> help(sapply)
lapply                  package:base                   R Documentation
 
Apply a Function over a List or Vector
 
Description:
 
     ‘lapply’ returns a list of the same length as ‘X’, each element of
     which is the result of applying ‘FUN’ to the corresponding element
     of ‘X’.
 
     ‘sapply’ is a user-friendly version and wrapper of ‘lapply’ by
     default returning a vector, matrix or, if ‘simplify = "array"’, an
     array if appropriate, by applying ‘simplify2array()’.  ‘sapply(x,
     f, simplify = FALSE, USE.NAMES = FALSE)’ is the same as ‘lapply(x,
     f)’.
 
     ‘vapply’ is similar to ‘sapply’, but has a pre-specified type of
     return value, so it can be safer (and sometimes faster) to use.
 
     ‘replicate’ is a wrapper for the common use of ‘sapply’ for
     repeated evaluation of an expression (which will usually involve
     random number generation).
 
     ‘simplify2array()’ is the utility called from ‘sapply()’ when
     ‘simplify’ is not false and is similarly called from ‘mapply()’.
 
Usage:
 
     lapply(X, FUN, ...)
 
     sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
 
     vapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)
 
     replicate(n, expr, simplify = "array")
 
     simplify2array(x, higher = TRUE)

Naši funkci pow pro výpočet n-té mocniny:

pow <- function(x, y=2) {
    result <- x ^ y
    return(result)
}

tedy můžeme postupně aplikovat na prvky sekvence s hodnotami 1, 2, … 10 s tím, že se výsledek „zjednoduší“ na seznam:

> sapply(1:10, pow)
 
 [1]   1   4   9  16  25  36  49  64  81 100

Pokud namísto funkce sapply použijeme funkci lapply, bude výpočet probíhat stejným způsobem, ale výsledek bude odlišný – vrátí se jednoprvkové seznamy s výsledky:

> lapply(1:10, pow)
 
[[1]]
[1] 1
 
[[2]]
[1] 4
 
[[3]]
[1] 9
 
[[4]]
[1] 16
 
[[5]]
[1] 25
 
[[6]]
[1] 36
 
[[7]]
[1] 49
 
[[8]]
[1] 64
 
[[9]]
[1] 81
 
[[10]]
[1] 100

8. Kombinace anonymní funkce a funkcí vyššího řádu sapply či lapply

Poměrně často se setkáme i s použitím anonymní funkce (viz šestou kapitolu) jakožto parametru funkce vyššího řádu sapply či lapply. Druhé mocniny hodnot 1..10 lze vypočítat i takto:

> sapply(1:10, function(x) x*x)
 
 [1]   1   4   9  16  25  36  49  64  81 100

Častěji se ovšem setkáme s tím, že je tělo funkce uzavřeno do složených závorek:

> sapply(1:10, function(x) {x*x})
 [1]   1   4   9  16  25  36  49  64  81 100

Popř. se použije konstrukce return, a to buď uvnitř složených závorek, nebo i bez nich:

> sapply(1:10, function(x) {return (x*x)})
 [1]   1   4   9  16  25  36  49  64  81 100
 
> sapply(1:10, function(x) return (x*x))
 [1]   1   4   9  16  25  36  49  64  81 100
Poznámka: naprosto stejným způsobem by se provedl zápis při použití lapply namísto sapply.

Kombinace více volání funkce sapply:

> sapply(1:10, function(x) x*x)
 [1] 25 16  9  4  1  0  1  4  9 16 25

9. Prostředí (environment)

Příkazy uvnitř těla funkce jsou vykonávány v rámci nějakého prostředí (environment). Toto prostředí určuje proměnné, které jsou v rámci těla funkce (nebo mimo něj) viditelné. Tyto dostupné (viditelné) proměnné lze zjistit s využitím funkce ls:

> help(ls)

Pokud tedy vytvoříme nějaké proměnné:

> a <- 1
> b <- 2
> f <- function(x) x<-0

Měla by funkce ls vrátit vektor s trojicí jmen těchto proměnných:

> ls()
 
[1] "a" "b" "f"
Poznámka: pokud se vrátí větší množství jmen, postačuje znovu spustit REPL programovacího jazyka R.

Viditelnost proměnných (a pojmenované funkce jsou taktéž proměnné) můžeme zjistit i v případě, že jedna funkce je vnořena do funkce jiné, což je pochopitelně možné (pokud by tomu tak nebylo, nebyly by funkce plnohodnotnými datovými typy – mnohé jazyky ovšem toto omezení mnohdy poněkud uměle zavádí):

f1 <- function(param_f1) {
    f2 <- function(param_f2) {
        print("f2")
        print(environment())
        print(ls())
    }
    f2(42)
    print("f1")
    print(environment())
    print(ls())
}
f1()

Vidíme, že uvnitř funkce můžeme vidět a tedy i přistupovat k jejím parametrům; interní funkce je považována za běžnou lokální proměnnou:

[1] "f2"
<environment: 0x55cf4d95fd58>
[1] "param_f2"
[1] "f1"
<environment: 0x55cf4d95ff18>
[1] "f2"       "param_f1"

Operátor ← již známe: používá se pro přiřazení hodnoty do proměnné, která je v případě potřeby vytvořena. Díky tomu, že každé volání funkce vytvoří nové prostředí, budou i proměnné vytvořené s využitím ← pouze lokální v rámci daného prostředí, což je většinou přesně takové chování, které požadujeme:

x <- 10
f3 <- function(param_f3) {
    x <- 20
    print(x)
    f4 <- function(param_f4) {
        x <- 30
        print(x)
    }
    f4()
    print(x)
}
print(x)
f3()
print(x)

Z výsledků je patrné, že jen první přiřazení bylo provedeno do globální proměnné x, zatímco druhé přiřazení se týká lokální proměnné funkce f3 a třetí přiřazení proměnné lokální v rámci funkce f4 (která je navíc sama lokálně viditelná jen ve funkci f3:

> print(x)
[1] 10
> f3()
[1] 20
[1] 30
[1] 20
> print(x)
[1] 10
Poznámka: opět se jedná o chování, které je ve většině mainstreamových programovacích jazyků přirozené.

10. Přístup k nelokálním proměnným

V některých případech (jeden takový uvidíme dále při implementaci čítače s využitím uzávěru) je nutné měnit hodnotu nelokálních proměnných. V takovém případě se namísto operátoru přiřazení ← použije operátor „superpřiřazení“, který se zapisuje <<-. Tento operátor postupně prochází dostupnými prostředími a hledá, zda daná proměnná již existuje či nikoli. Pokud tedy v předchozím příkladu použijeme operátor „superpřiřazení“, změní se i jeho chování, a to poměrně zásadním způsobem:

x <- 10
f5 <- function(param_f3) {
    x <<- 20
    print(x)
    f6 <- function(param_f4) {
        x <<- 30
        print(x)
    }
    f6()
    print(x)
}
print(x)
f5()
print(x)

Chování lze sledovat z výstupu:

> print(x)
[1] 10
> f5()
[1] 20
[1] 30
[1] 30
> print(x)
[1] 30

Můžeme vidět, že se nejdříve vypíše hodnota globální proměnné (10), dále se tato hodnota ve funkci f5 změní na 20, v dalším kroku ve funkci f6 dojde ke změně na 30 a tato hodnota je již zachována. Operátor <<- nám tedy umožnil změnit hodnotu globální proměnné (což je ovšem obecně problematický rys, který by se neměl zneužívat).

11. Lexikální uzávěry

Připomeňme si, že v programovacím jazyce R jsou funkce považovány za plnohodnotné datové typy, což znamená, že funkce lze navázat na libovolný symbol (a tím vlastně původně anonymní funkci pojmenovat), funkce lze předávat jako parametry do jiných funkcí a funkce mohou být taktéž návratovou hodnotou jiných funkcí – funkce tedy může vytvořit a vrátit jinou funkci. R taktéž podporuje práci s uzávěry (closure(s)), tj. funkcí svázaných s nějakým symbolem vytvořeným vně funkce.

Podpora uzávěrů umožňuje například tvorbu funkcí sdílejících společný kontext (GUI) atd. Ovšem vzhledem k tomu, že – jak již víme – R není čistě funkcionálním jazykem, je možné při vytváření uživatelských funkcí přímo z dané funkce přistupovat k nějakému globálnímu symbolu, přesněji řečeno k symbolu „globálnímu“ v rámci nějakého jmenného prostoru. Taktéž lze vytvářet funkce s vedlejším efektem, které například zapisují data do souborů, mění hodnotu navázanou na globální symboly atd.

Podívejme se na příklad jednoduchého, ale praktického využití uzávěrů. Jedná se o konstruktor funkcí „výpočet n-té mocniny“, kde n je specifikováno při konstrukci funkce:

pow_x <- function(x) {
    function(y) { y ^ x }
}

Můžeme si například nechat vytvořit funkci pro výpočet druhé mocniny. Vytvoření (konstrukce) takové funkce vypadá následovně:

> square <- pow_x(2)

Následně již můžeme novou (pojmenovanou!) funkci použít stejně, jako jakoukoli jinou funkci:

> square(3)
9

Další použití, tentokrát pro sekvenci hodnot:

> sapply(1:10, square)
 
 [1]    2    4    8   16   32   64  128  256  512 1024

Více zkonstruovaných funkcí:

pow_x <- function(x) {
        function(y) { y ^ x }
}
 
linear <- pow_x(1)
square <- pow_x(2)
cube <- pow_x(3)
 
for (x in 1:10) {
    print(c(x, linear(x), square(x), cube(x)))
}

S výsledkem:

[1]  1   1    1    1
[1]  2   2    4    8
[1]  3   3    9   27
[1]  4   4   16   64
[1]  5   5   25  125
[1]  6   6   36  216
[1]  7   7   49  343
[1]  8   8   64  512
[1]  9   9   81  729
[1]  10 10  100 1000
Poznámka: lexical scope má ovšem dalekosáhlejší důsledky, které mj. ovlivňují činnost správce paměti atd. Jde o to, že pokud je nějaká proměnná (která je definovaná vně funkce) na funkci navázána (prakticky: je ve funkci použita), nemůže tato proměnná zaniknout ani při opuštění daného bloku, protože společně s funkcí tvoří takzvaný uzávěr (closure).

12. Klasický příklad uzávěru – čítač (generátor sekvence)

Podívejme se nyní na dnes již zcela klasický příklad využití uzávěru. Jedná se o implementaci čítače (nebo obecněji generátoru nějaké sekvence hodnot, který pro svoji funkci potřebuje interní paměť pro zapamatování svého stavu). Čítač je představován uzávěrem zkonstruovaným funkcí counter. Funkce v uzávěru přistupuje k navázané proměnné n, kterou zvyšuje o jedničku a současně její hodnotu vrací:

counter <- function() {
    n <- 0
    function() {
        n <<- n + 1
        n
    }
}

Čítač si nejprve necháme zkonstruovat:

> c1 <- counter()

Volání counter() vrátilo uzávěr, při jehož zavolání dojde ke změně vnitřního stavu a posléze se vrátí nová hodnota čítače:

> c1()
[1] 1
 
> c1()
[1] 2
 
> c1()
[1] 3

Interní hodnota čítače v žádném případě není obdobou statických lokálních proměnných z céčka, o čemž se můžeme snadno přesvědčit vytvořením dalších dvou na sobě nezávislých čítačů:

> c2 <- counter()
> c3 <- counter()

Všechny tři čítače skutečně pracují nezávisle na sobě:

> c1()
[1] 4
> c2()
[1] 1
> c3()
[1] 1
 
> c1()
[1] 5
> c2()
[1] 2
> c3()
[1] 2
 
> c1()
[1] 6
> c2()
[1] 3
> c3()
[1] 3

13. Čítač s předem nastaveným krokem

Předchozí uzávěr pracoval s navázanou proměnnou n, ovšem můžeme vytvořit i uzávěr, který pracuje s hodnotu svého parametru. V praxi si například můžeme vytvořit čítač, u něhož je možné specifikovat krok. Jedná z možných implementací může vypadat následovně:

counter <- function(step=1) {
    n <- 0
    function() {
        n <<- n + step
        n
    }
}

Nový typ čítače si můžeme snadno otestovat:

> c0 <- counter(2)
 
> c0()
[1] 2
 
> c0()
[1] 4
 
> c0()
[1] 6
 
> c0()
[1] 8

Několik na sobě nezávislých čítačů, každý s jiným krokem:

c1 <- counter(1)
c2 <- counter(2)
c3 <- counter(3)
c4 <- counter(4)

Nové čítače použijeme – opět budou na sobě nezávislé:

for (i in 1:10) {
    print(c(c1(), c2(), c3(), c4()))
}
 
[1]  1  2  3  4
[1]  2  4  6  8
[1]  3  6  9 12
[1]  4  8 12 16
[1]  5 10 15 20
[1]  6 12 18 24
[1]  7 14 21 28
[1]  8 16 24 32
[1]  9 18 27 36
[1] 10 20 30 40

14. Rekurzivní funkce

Naprostá většina dnes používaných mainstreamových programovacích jazyků podporuje tvorbu rekurzivních funkcí. Výjimkou není ani jazyk R, takže si ukažme typickou funkci, která se používá při výuce programování. Jedná se o rekurzivní variantu výpočtu faktoriálu:

fact <- function(n)
{
    if (n == 0 || n == 1) {
        return (1)
    } else {
        return (n *  fact(n - 1))
    }
}

Otestování funkcionality:

> fact(10)
 
[1] 3628800

Výpočet faktoriálů vstupních hodnot od 1 do 10:

> lapply(1:10, fact)
 
[[1]]
[1] 1
 
[[2]]
[1] 2
 
[[3]]
[1] 6
 
[[4]]
[1] 24
 
[[5]]
[1] 120
 
[[6]]
[1] 720
 
[[7]]
[1] 5040
 
[[8]]
[1] 40320
 
[[9]]
[1] 362880
 
[[10]]
[1] 3628800

Vzhledem k tomu, že se jedná o rekurzivní funkci bez aplikovaného TCO (tail call optimization), dojde pro větší vstupní hodnoty k vyčerpání paměti určené pro implementaci zásobníku, resp. přesněji řečeno zásobníkových rámců:

> fact(10000)
 
Error: C stack usage  7978740 is too close to the limit

Podporována je i nepřímá rekurze, tedy stav, kdy jedna funkce volá druhou a ta zase první:

f1 <- function(x) {
    print(x)
    if (x>0) {
        f2(x-1)
    }
    0
}
 
f2 <- function(x) {
    print(x)
    f1(x/2)
}

Otestování:

> f2(10)
 
[1] 10
[1] 5
[1] 4
[1] 2
[1] 1
[1] 0.5
[1] -0.5
[1] -0.25
[1] 0

15. Funkce vyššího řádu v programovacím jazyce R

Programovací jazyk R sice není, na rozdíl od Haskellu a částečně i od programovacího jazyka Clojure, čistě funkcionálním jazykem, nicméně i zde mohou hrát při vývoji aplikací poměrně velkou roli takzvané funkce vyššího řádu (higher order functions), což jsou funkce, které jako své parametry akceptují jiné funkce, popř. dokonce vrací (nové) funkce jako svoji návratovou hodnotu. Mezi dvě základní funkce vyššího řádu, které nalezneme prakticky ve všech dialektech programovacího jazyka Lisp (a připomeňme si, že R vychází ze Scheme, tedy z jedné varianty LISPu), patří funkce nazvané Reduce, Filter a Map. Kromě toho lze používat i další funkce vyššího řádu, například Find či Negate:

Reduce(f, x, init, right = FALSE, accumulate = FALSE)
 
Filter(f, x)
 
Find(f, x, right = FALSE, nomatch = NULL)
 
Map(f, ...)
 
Negate(f)
 
Position(f, x, right = FALSE, nomatch = NA_integer_)

S použitím funkcí vyššího řádu se seznámíme v navazujících kapitolách.

16. Funkce Reduce

Dvěma základními funkcemi vyššího řádu, které nesmějí chybět v repertoáru žádné funkcionálně zaměřené knihovny, je dvojice funkcí typicky pojmenovaná reduce a reduceRight (někdy se setkáme s názvy foldl a foldr atd.). Názvy těchto funkcí naznačují jejich účel – dochází k postupné redukci prvků uložených v kolekci či v poli, a to (postupnou) aplikací zvolené uživatelské funkce na jednotlivé prvky a po krocích počítaný mezivýsledek. Mezi reduce a reduceRight je rozdíl v tom, ze které strany původní kolekce dochází ke kýžené redukci.

Podívejme se nyní na typický „školní“ příklad, v němž se sečtou všechny prvky v aritmetické řadě 1..10. Nejprve vytvořme tuto řadu:

s <- 1:10

Následně vytvořme uživatelskou funkci, která se bude volat pro každý prvek původní kolekce a pro mezivýsledek. Jedná se o značně jednoduchou funkci, které pouze obě předané hodnoty sečte:

add <- function(x, y) {
    x+y
}

Nyní zajistíme postupné volání funkce add na prvky sekvence s automatickým předáním mezivýsledku. Podle předpokladů bude výsledek funkce reduce v tomto případě totožný s výsledkem vráceným funkcí typu reduceRight, protože je zcela jedno, v jakém pořadí se prvky sečtou:

Reduce(add, s)
55

Následuje nepatrně složitější příklad – výpočet tabulky faktoriálů pro vstupy od 1 do 10 (včetně):

mul <- function(x, y) {
    x*y
}
 
fact <- function(n) {
    Reduce(mul, 1:n)
}
 
sapply(1:10, fact)

17. Redukce zprava

Jazyk R ve své základní knihovně neobsahuje přímo funkci pro redukci sekvence zprava, tedy funkci, která se běžně nazývá reduceRight. Namísto toho je možné funkci Reduce předat parametr right:

s <- 1:10
 
add <- function(x, y) {
    x+y
}
 
Reduce(add, s, right=TRUE)

Ne všechny operace jsou ovšem asociativní a komutativní, jako je tomu u součtu čísel. Zkusme si vyzkoušet, co se stane ve chvíli, kdy namísto sčítání čísel budeme používat umocnění. Zde je rozdíl mezi redukcí zleva a redukcí zleva jasně patrný:

Root tip obecný

s <- c(2, 2, 3)
 
pow <- function(x, y) {
    x^y
}
 
Reduce(pow, s)
[1] 64
 
Reduce(pow, s, right=TRUE)
[1] 256

18. Balíčky s alternativní formou definice funkcí

Do programovacího jazyka R je možné relativně snadno přidávat další konstrukce. Týká se to i definice, popř. volání funkcí, a to i funkcí anonymních. V současnosti existuje hned několik balíčků s alternativní podobou definice funkcí. Tyto balíčky jsou zmíněny v tabulce a některým z nich se budeme věnovat v následujícím pokračování tohoto seriálu:

# Balíček Forma Funkce s jedním parametrem Funkce se dvěma parametry Explicitní parametry Jména parametrů
1 base r function function(x) x + 1 function(x, y) x + y Ano Explicitní
2 rlang as_function as_function(~.x + 1)) as_function(~.x+.y) Ne Implicitní. jen .x or .y
3 pryr f (implicitní parametry) f(x + 1) f(x + y) Ne Implicitní, odvozeno z těla funkce
4 pryr f (explicitní parametry) f(x, x + 1) f(x, y, x + y) Ano Explicitní
5 nofrills fn fn(x ~ x + 1) fn(x, y ~ x + y) Ano Explicitní
6 gsubfn as.function.formula (implicitní parametry) as.function.formula(~ x + 1) as.function.formula(~ x + y) Ne Implicitní, odvozeno z pravé strany výrazu
7 gsubfn as.function.formula (explicitní parametry) as.function.formula(x ~ x + 1) as.function.formula(x + y ~ x + y + z) Ano Explicitní, odvozeno z levé strany výrazu
8 wrapr lambda lambda(x, x + 1) lambda(x, y, x + y) Ano Explicitní
9 lambda f f(.(x) + 1) f(.(x) + .(y)) Ne Implicitní, odvozeno z výrazu
10 lambdass ~~ ~~ ..1 + 1 ~~ ..1 + ..2 No Implicitní, povoleno použití ..N zápisu
11 lambdass f.() f.(x, x + 1) f.(x, y, x + y) Ano Explicitní
12 lambdass %->% f(x) %->% {x + 1} f(x, y) %->% {x + y} Ano Explicitní
13 functional “->” NA x ~ y → x + y Ano Explicitní
14 ne (ve fázi návrhu) lambda lambda(x ~ x + 1L) lambda(x + y ~ x + y) Ano Explicitní, odvozeno z levé strany výrazu
15 ne (ve fázi návrhu) lambda lambda(x:x + 1) lambda(x, y:x + y) Ano Explicitní
16 ne (ve fázi návrhu) [] -> [x] → x + 1 [x, y] → x + y Ano Explicitní
Poznámka: pro většinu uživatelů programovacího jazyka R je však původní způsob definice funkcí (první řádek tabulky) dostačující. Zajímavý je návrh z patnáctého řádku, popř. způsob používaný v balíčku wrapr.

19. Repositář s demonstračními příklady

Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/r-examples V případě, že z nějakého důvodu nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má stále jen jednotky kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:

# Demonstrační příklad Stručný popis demonstračního příkladu Cesta
1 empty_function.R prázdná funkce bez parametrů (nejjednodušší příklad pojmenované funkce) https://github.com/tisnik/r-examples/blob/master/14-language-features/empty_function.R
2 function_type.R funkce je plnohodnotným datovým typem https://github.com/tisnik/r-examples/blob/master/14-language-features/function_type.R
3 add.R součet, implicitní return https://github.com/tisnik/r-examples/blob/master/14-language-features/add.R
4 add2.R více příkazů ve funkci, implicitní return https://github.com/tisnik/r-examples/blob/master/14-language-features/add2.R
5 classify_number1.R funkce s jedním příkazem return https://github.com/tisnik/r-examples/blob/master/14-language-features/classify_number1.R
6 classify_number2.R funkce s více příkazy return https://github.com/tisnik/r-examples/blob/master/14-language-features/classify_number2.R
7 default_values.R https://github.com/tisnik/r-examples/blob/master/14-language-features/default_values.R
8 implicit_return_value.R nepovinné parametry s výchozí hodnotou https://github.com/tisnik/r-examples/blob/master/14-language-features/implicit_return_value.R
9 explicit_return_value_error.R chybný zápis příkazu return https://github.com/tisnik/r-examples/blob/master/14-language-features/explicit_return_value_error.R
10 explicit_return_value.R korektní zápis příkazu return https://github.com/tisnik/r-examples/blob/master/14-language-features/explicit_return_value.R
11 pow.R výpočet mocniny formou primitivní funkce https://github.com/tisnik/r-examples/blob/master/14-language-features/pow.R
12 pow_closure.R výpočet mocniny formou uzávěru https://github.com/tisnik/r-examples/blob/master/14-language-features/pow_closure.R
13 counter_closure.R čítač implementovaný uzávěrem https://github.com/tisnik/r-examples/blob/master/14-language-features/counter_closure.R
14 counter2_closure.R čítač s krokem implementovaný uzávěrem https://github.com/tisnik/r-examples/blob/master/14-language-features/counter2_closure.R

20. Odkazy na Internetu

  1. R Tutorial
    https://www.tutorialspoin­t.com/r/index.htm
  2. A Tutorial on Using Functions in R!
    https://www.datacamp.com/com­munity/tutorials/functions-in-r-a-tutorial
  3. R Functions
    https://www.datamentor.io/r-programming/function/
  4. A Tutorial on Loops in R – Usage and Alternatives
    https://www.datacamp.com/com­munity/tutorials/tutorial-on-loops-in-r
  5. Anonymous Functions in R – Part 1
    https://coolbutuseless.git­hub.io/2019/03/13/anonymous-functions-in-r-part-1/
  6. Anonymous Functions in R – Part 2
    https://coolbutuseless.git­hub.io/2019/03/13/anonymous-functions-in-r-part-2/
  7. Scoping and Closures in R
    https://www.pluralsight.com/gu­ides/scoping-and-closures-in-r
  8. Tools for Computing on the Language
    https://www.rdocumentation­.org/packages/pryr/version­s/0.1.4
  9. Difference between double-precision data type and numeric data type
    https://stackoverflow.com/qu­estions/50255318/differen­ce-between-double-precision-data-type-and-numeric-data-type
  10. R Data Types
    https://www.w3schools.in/r/data-types/
  11. What is the difference between mode and class in R?
    https://stackoverflow.com/qu­estions/35445112/what-is-the-difference-between-mode-and-class-in-r
  12. switch: Select One of a List of Alternatives
    https://rdrr.io/r/base/switch.html
  13. R switch() Function
    https://www.datamentor.io/r-programming/switch-function/
  14. Using ggplot in Python: Visualizing Data With plotnine
    https://realpython.com/ggplot-python/
  15. A Grammar of Graphics for Python
    https://plotnine.readthedoc­s.io/en/stable/
  16. Plotnine gallery
    https://plotnine.readthedoc­s.io/en/latest/gallery.html
  17. plotnine 0.7.1 na PyPi
    https://pypi.org/project/plotnine/
  18. plotnine-examples 0.0.4 na PyPi
    https://pypi.org/project/plotnine-examples/
  19. plotnine examples repository
    https://github.com/has2k1/plotnine-examples
  20. Data visualization in R: cheat sheet
    https://github.com/rstudi­o/cheatsheets/blob/master/da­ta-visualization-2.1.pdf
  21. The R Project for Statistical Computing
    https://www.r-project.org/
  22. An Introduction to R
    https://cran.r-project.org/doc/manuals/r-release/R-intro.pdf
  23. R (programming language)
    https://en.wikipedia.org/wi­ki/R_(programming_language)
  24. The R Programming Language
    https://www.tiobe.com/tiobe-index/r/
  25. R Graphics Second Edition
    https://www.stat.auckland­.ac.nz/~paul/RG2e/
  26. ggplot2 – Introduction
    https://www.tutorialspoin­t.com/ggplot2/ggplot2_intro­duction.htm
  27. ggplot2: Elegant Graphics for Data Analysis
    https://ggplot2-book.org/index.html
  28. Create Elegant Data Visualisations Using the Grammar of Graphics
    https://www.rdocumentation­.org/packages/ggplot2/ver­sions/3.3.2
  29. Grid
    https://www.stat.auckland­.ac.nz/~paul/grid/grid.html
  30. Interactive Course: Data Visualization with lattice in R
    https://www.datacamp.com/courses/data-visualization-in-r-with-lattice
  31. Lattice: trellis graphics for R
    https://lattice.r-forge.r-project.org/
  32. Lattice: Multivariate Data Visualization with R
    http://lmdvr.r-forge.r-project.org/figures/figures.html
  33. Getting Started with Lattice Graphics
    https://lattice.r-forge.r-project.org/Vignettes/src/lattice-intro/lattice-intro.pdf
  34. Using lattice’s xyplot()
    https://homerhanumat.github­.io/tigerstats/xyplot.html
  35. ggplot2 Tutorial
    https://www.tutorialspoin­t.com/ggplot2/index.htm
  36. Lattice Package in R with Functions and Graphs
    https://techvidvan.com/tu­torials/lattice-package-in-r/
  37. The R Graph Gallery
    https://www.r-graph-gallery.com/index.html
  38. Lattice Graphs
    https://www.statmethods.net/ad­vgraphs/trellis.html
  39. ggplot2 (Graph gallery)
    https://www.r-graph-gallery.com/ggplot2-package.html
  40. R Markdown
    https://rmarkdown.rstudio.com/
  41. R Markdown: The Definitive Guide
    https://bookdown.org/yihui/rmarkdown/
  42. R Markdown Cheat Sheet
    https://rstudio.com/wp-content/uploads/2016/03/rmarkdown-cheatsheet-2.0.pdf
  43. Introduction to R Markdown
    https://rmarkdown.rstudio­.com/articles_intro.html
  44. R Cheat Sheets
    https://blog.sergiouri.be/2016/07/r-cheat-sheets.html
  45. R Cheat Sheet
    https://s3.amazonaws.com/quandl-static-content/Documents/Quandl±+R+Che­at+Sheet.pdf
  46. Base R Cheat Sheet
    https://rstudio.com/wp-content/uploads/2016/06/r-cheat-sheet.pdf
  47. PYPL PopularitY of Programming Language
    https://pypl.github.io/PYPL.html
  48. Tiobe index
    https://www.tiobe.com/tiobe-index/
  49. Stack Overflow: Most Loved, Dreaded & Wanted Programming Languages In 2020
    https://fossbytes.com/stack-overflow-most-loved-dreaded-wanted-programming-languages-in-2020/
  50. How to Install and Use R on Ubuntu
    https://itsfoss.com/install-r-ubuntu/
  51. R programming for beginners – Why you should use R
    https://www.youtube.com/wat­ch?v=9kYUGMg_14s
  52. GOTO 2012 • The R Language The Good The Bad & The Ugly
    https://www.youtube.com/wat­ch?v=6S9r_YbqHy8
  53. Intro to Data Visualization with R & ggplot2
    https://www.youtube.com/wat­ch?v=49fADBfcDD4
  54. Plotting with ggplot2: Part 1
    https://www.youtube.com/wat­ch?v=HeqHMM4ziXA
  55. Plotting with ggplot2: Part 2
    https://www.youtube.com/wat­ch?v=n8kYa9vu1l8
  56. R vs Python – What should I learn in 2020? | R and Python Comparison
    https://www.youtube.com/wat­ch?v=eRP_J2yLjSU
  57. R Programming 101
    https://www.youtube.com/c/rpro­gramming101
  58. Seriál Tvorba grafů pomocí programu „R“
    https://www.root.cz/serialy/tvorba-grafu-pomoci-programu-r/
  59. Tvorba grafů pomocí programu „R“: úvod
    https://www.root.cz/clanky/tvorba-grafu-pomoci-programu-r-1/
  60. Tvorba grafů pomocí programu „R“: pokročilé funkce
    https://www.root.cz/clanky/tvorba-grafu-pomoci-programu-r-pokrocile-funkce/
  61. Tvorba grafů pomocí programu „R“: vkládání textu, čeština
    https://www.root.cz/clanky/grafy-pomoci-programu-r-vkladani-textu-cestina/
  62. Cesta erka: Krok nultý – instalace & nastavení – prostředí, projekty, package
    https://www.jla-data.net/r4su/r4su-environment-setup/
  63. Cesta erka: Krok první – operace a struktury – proměnné, rovnítka a dolary
    https://www.jla-data.net/r4su/r4su-data-structures/
  64. Cesta erka: Krok druhý – načtení externích dat – csvčka, excely a databáze
    https://www.jla-data.net/r4su/r4su-read-data/
  65. Cesta erka: Krok třetí – manipulace s daty – dplyr, slovesa a pajpy
    https://www.jla-data.net/r4su/r4su-manipulate-data/
  66. Cesta erka: Krok čtvrtý – podání výsledků – ggplot, geomy a estetiky
    https://www.jla-data.net/r4su/r4su-report-results/
  67. Cesta erka: Krok pátý – case study – případ piva v Praze
    https://www.jla-data.net/r4su/r4su-case-study-beer/
  68. V indexu popularity programovacích jazyků TIOBE překvapilo R, Go, Perl, Scratch a Rust
    https://www.root.cz/zpravicky/v-indexu-popularity-programovacich-jazyku-tiobe-prekvapilo-r-go-perl-scratch-a-rust/
  69. Is R Programming SURGING in Popularity in 2020?
    https://www.youtube.com/watch?v=Duwn-vImyXE
  70. Using the R programming language in Jupyter Notebook
    https://docs.anaconda.com/a­naconda/navigator/tutorial­s/r-lang/
  71. Using R on Jupyter Notebook
    https://dzone.com/articles/using-r-on-jupyternbspnotebook
  72. Graphics, ggplot2
    http://r4stats.com/examples/graphics-ggplot2/
  73. A Practice Data Set
    https://r4stats.wordpress­.com/examples/mydata/
  74. Shiny – galerie projektů
    https://shiny.rstudio.com/gallery/
  75. Seriál Programovací jazyk Julia
    https://www.root.cz/seria­ly/programovaci-jazyk-julia/
  76. Julia (front page)
    http://julialang.org/
  77. Julia – repositář na GitHubu
    https://github.com/JuliaLang/julia
  78. Julia (programming language)
    https://en.wikipedia.org/wi­ki/Julia_%28programming_lan­guage%29
  79. IJulia
    https://github.com/JuliaLan­g/IJulia.jl
  80. Introducing Julia
    https://en.wikibooks.org/wi­ki/Introducing_Julia
  81. Julia: the REPL
    https://en.wikibooks.org/wi­ki/Introducing_Julia/The_REPL
  82. Introducing Julia/Metaprogramming
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Meta­programming
  83. Month of Julia
    https://github.com/DataWo­okie/MonthOfJulia
  84. Learn X in Y minutes (where X=Julia)
    https://learnxinyminutes.com/doc­s/julia/
  85. New Julia language seeks to be the C for scientists
    http://www.infoworld.com/ar­ticle/2616709/application-development/new-julia-language-seeks-to-be-the-c-for-scientists.html
  86. Julia: A Fast Dynamic Language for Technical Computing
    http://karpinski.org/publi­cations/2012/julia-a-fast-dynamic-language
  87. The LLVM Compiler Infrastructure
    http://llvm.org/
  88. Julia: benchmarks
    http://julialang.org/benchmarks/
  89. R Vector
    https://www.datamentor.io/r-programming/vector/
  90. .R File Extension
    https://fileinfo.com/extension/r
  91. Lineární regrese
    https://cs.wikipedia.org/wi­ki/Line%C3%A1rn%C3%AD_regre­se
  92. lm (funkce)
    https://www.rdocumentation­.org/packages/stats/versi­ons/3.6.2/topics/lm
  93. quit (funkce)
    https://www.rdocumentation­.org/packages/base/version­s/3.6.2/topics/quit
  94. c (funkce)
    https://www.rdocumentation­.org/packages/base/version­s/3.6.2/topics/c
  95. help (funkce)
    https://www.rdocumentation­.org/packages/utils/versi­ons/3.6.2/topics/help
  96. Shiny: Introduction to interactive documents
    https://shiny.rstudio.com/ar­ticles/interactive-docs.html
  97. R Release History 1997–2013
    http://timelyportfolio.git­hub.io/rCharts_timeline_r/
  98. R: atomic vectors
    https://renenyffenegger.ch/no­tes/development/languages/R/da­ta-structures/vector/
  99. 11 Best R Programming IDE and editors
    https://www.dunebook.com/best-r-programming-ide/
  100. CRAN – The Comprehensive R Archive Network
    https://cran.r-project.org/
  101. R – Arrays
    https://www.tutorialspoin­t.com/r/r_arrays.htm
  102. Array vs Matrix in R Programming
    https://www.geeksforgeeks.org/array-vs-matrix-in-r-programming/?ref=rp
  103. Online R Language IDE
    https://www.jdoodle.com/execute-r-online/
  104. Execute R Online (R v3.4.1)
    https://www.tutorialspoin­t.com/execute_r_online.php
  105. Snippets: Run any R code you like. There are over twelve thousand R packages preloaded
    https://rdrr.io/snippets/
  106. R Package Documentation
    https://rdrr.io/
  107. Data Reshaping in R – Popular Functions to Organise Data
    https://techvidvan.com/tutorials/data-reshaping-in-r/
  108. What is an R Data Frame?
    https://magoosh.com/data-science/what-is-an-r-data-frame/
  109. What's a data frame?
    https://campus.datacamp.com/cou­rses/free-introduction-to-r/chapter-5-data-frames?ex=1
  110. data.frame
    https://www.rdocumentation­.org/packages/base/version­s/3.6.2/topics/data.frame
  111. as.data.frame
    https://www.rdocumentation­.org/packages/base/version­s/3.6.2/topics/as.data.fra­me
  112. table
    https://www.rdocumentation­.org/packages/base/version­s/3.6.2/topics/table
  113. Python Pandas – DataFrame
    https://www.tutorialspoin­t.com/python_pandas/python_pan­das_dataframe.htm
  114. The Pandas DataFrame: Make Working With Data Delightful
    https://realpython.com/pandas-dataframe/
  115. Python | Pandas DataFrame
    https://www.geeksforgeeks.org/python-pandas-dataframe/
  116. R – Factors
    https://www.tutorialspoin­t.com/r/r_factors.htm
  117. R – Scatterplots
    https://www.tutorialspoin­t.com/r/r_scatterplots.htm
  118. Quick guide to line types (lty) in R
    https://www.benjaminbell.co­.uk/2018/02/quick-guide-to-line-types-lty-in-r.html
  119. Lattice C (Wikipedia)
    https://en.wikipedia.org/wi­ki/Lattice_C
  120. Lorenz Attractor in R
    https://www.sixhat.net/lorenz-attractor-in-r.html
  121. Small multiple
    https://en.wikipedia.org/wi­ki/Small_multiple
  122. Category:Infographics (infografika)
    https://en.wikipedia.org/wi­ki/Category:Infographics
  123. Trellis plots (pro Python)
    https://subscription.packtpub­.com/book/big_data_and_bu­siness_intelligence/9781784390150/4/ch04l­vl1sec41/trellis-plots
  124. Trellis (architecture)
    https://en.wikipedia.org/wi­ki/Trellis_(architecture)
  125. Izobara (meteorologie)
    https://cs.wikipedia.org/wi­ki/Izobara_(meteorologie)
  126. How to Create a Lattice Plot in R
    https://www.dummies.com/pro­gramming/r/how-to-create-a-lattice-plot-in-r/
  127. Density estimation
    https://en.wikipedia.org/wi­ki/Density_estimation
  128. Sedm smrtelných statistických hříchů
    http://dfens-cz.com/sedm-smrtelnych-statistickych-hrichu/
  129. Spurious correlations
    https://tylervigen.com/spurious-correlations
  130. R programming
    https://www.slideshare.net/shan­tanupatil104/r-programming-44637606
  131. R language tutorial
    https://www.slideshare.net/ChiuYW/r-language-tutorial
  132. An Interactive Introduction To R (Programming Language For Statistics)
    https://www.slideshare.net/da­taspora/an-interactive-introduction-to-r-programming-language-for-statistics
  133. A Pamphlet against R
    https://panicz.github.io/pamphlet/
  134. Notebook interface
    https://en.wikipedia.org/wi­ki/Notebook_interface
  135. Jypyter: open source, interactive data science and scientific computing across over 40 programming languages
    https://jupyter.org/
  136. nbviewer: a simple way to share Jupyter Notebooks
    https://nbviewer.jupyter.org/
  137. Video streaming in the Jupyter Notebook
    https://towardsdatascience.com/video-streaming-in-the-jupyter-notebook-635bc5809e85
  138. How IPython and Jupyter Notebook work
    https://jupyter.readthedoc­s.io/en/latest/architectu­re/how_jupyter_ipython_wor­k.html
  139. Jupyter kernels
    https://github.com/jupyter/ju­pyter/wiki/Jupyter-kernels
  140. PNG is Not GIF
    https://www.root.cz/clanky/png-is-not-gif/
  141. Anatomie grafického formátu PNG
    https://www.root.cz/clanky/anatomie-grafickeho-formatu-png/
  142. PNG – bity, byty, chunky
    https://www.root.cz/clanky/png-bity-byty-chunky/
  143. Řádkové filtry v PNG
    https://www.root.cz/clanky/radkove-filtry-v-png/
  144. Nepovinné chunky v PNG a kontrola pomocí CRC
    https://www.root.cz/clanky/nepovinne-chunky-v-png-a-kontrola-pomoci-crc/

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.