Střípky funkcionálního programování a PHP (1)

2. 8. 2013 | #tutorial #php

Funkcionalní programování se stává v poslední době čím dál více populárnější a prvky funkcionálního paradigmatu lze vidět v mnoha jazycích – hodně profláklé jsou kupříkladu lambda výrazy, jejichž podporu lze nalézt v mnoha moderních jazycích, ale to samozřejmě není vše.

Absolvovat nějaký kurz nebo věnovat čas některému z čistě funkcionálních jazyků, může člověku ukázat nový směr myšlení při návrhu algoritmů a dle mého názoru rozšiřuje schopnosti komplexního myšlení nad řešením některých problémů. Ja sám jsem absolvoval ve škole hodně přínosný kurz Úvodu do funkcionálního programování, kde jsme pracovali s Haskellem. A velmi se mi tam zalíbily některé koncepty, které lze určitým způsobem použít i v PHP.

Pro ty, kteří se s funkcionálním paradigmatem nikdy nesetkali a neznají jeho vlastnosti a specifika, tak těm doporučím trochu pogooglit a vyhledat si nějaké zdroje. A není od věci si třeba něco i zkusit. Kdyby měl někdo zájem vyzkoušet Haskell, pak silně doporučuji http://naucte-se.haskell.cz/ a online interpreter [http://tryhaskell.org/], který obsahuje také minimálně základní lekce.

A teď už se vraťme k PHP a ukažme si některé koncepty:

Map

Map je asi všeobecně známá funkce, která aplikuje danou funkci na prvky listu – tak je to alespoň v Haskellu. V PHP se jedná o funkci array_map, která aplikuje danou funkci na pole prvků.

$addFunction = function ($item) {
  return $item + 1;
}

$numbers = [1,2,3];

$output = array_map($addFunction, $numbers)

// $output = [2,3,4];

Vidíme, že po aplikaci funkce pro přičtení jedničky, dostaneme pole, kde každý prvek z původního pole je větší o jedna. Není to žádná magie, ale byli by jste možná překvapeni, jak hodně vývojářů by něco takévho napsalo v konstrukci spjaté třeba s foreach. Řada konstrukcí, kde pouze transformujeme prvky pole přes nějakou funkci, lze velmi pohodlně řešit pomoci array_map.

Co kdybychom ale chtěli, abychom mohli ovlivnit, jaká hodnota bude přičtena každému prvku, přičemž bychom nebyli fixování na hodnotu 1?

Pak lze provést jednoduchou úpravu:

$addition = 5;

$addFunction = function ($item) use ($addition) {
  return $item + $addition;
}

$numbers = [1,2,3];

$output = array_map($addFunction, $numbers)

// $output = [6,7,8];

Myslím, že je všem zřejmé, co jsme právě udělali. Umožnili jsme měnit vnitřní scope funkce $addFunction. Ale mě se tohle řešení stále nelíbí, proto ho ještě upravíme k naprosté dokonalosti.

function add($addition) {
  return function ($item) use ($addition) {
    return $item + $addition;
}

}

$numbers = [1,2,3];

$output = array_map(add(10), $numbers)

// $output = [11,12,13];

Vytvořili jsme funkci add, jejimž výstupem je funkce, která přičte k vstupnímu argumentu takovou hodnotu, kterou si určíme. Díky tomu máme zcela univerzální funkci, jejiž chování můžeme upravovat dle libosti a přitom snadno aplikovat třeba pomoci array_map.

Filter

Další známou funkcí je funkce filter, která filtruje prvky listu a vrací list, který obahuje jen ty prvky, které daná funkce aplikuje. V PHP na to máme opět funkci array_filter, která provádí prakticky to samé.

Ukázka:

$greaterThan = function ($item) {
  return $item > 1;
}

$numbers = [1,2,3]

$output = array_filter($numbers, $greaterThan)

// $output = [2,3];

Funkce $greaterThan vrací true, právě tehdy, když vstupem funkce je hodnota větší než jedna. A array_filter tuto funkci aplikuje a filtruje tak prvky pole $numbers. Podle mě naprosto jasné.

Pokročilejší verze tak jako u mapu:

function greaterThan($bound) {
  return function ($item) use ($bound) {
    return $item > $bound;
}

}

$numbers = [1,2,3];

$output = array_filter($numbers, greaterThan(2))

// $output = [3];

A takhle jsme získali vcelku univerzální filter graterThan, který vrací true právě pro ty hodnoty, které jsou větší než vstupní argument.

Pokračování příště

Tím bych pro tento příspěvek skončil. Pro příště bych rád ukázal věci sousvisející s curryfikací a částečně aplikovanými funkcemi. A taky bych rád ukázal, jak v PHP můžeme vlastně skládat funkce.

Diskuse

comments powered by Disqus

Tento web používá k poskytování služeb, personalizaci reklam a analýze návštěvnosti soubory cookie. Používáním tohoto webu s tím souhlasíte. Další informace