fn: Lazy loading, currying, etc.
Met deze kleine library heb ik wat van Haskell's (en functioneel programmeren) beste features naar PHP willen halen.
Currying
De eerste feature is currying. Dat betekend dat je maar een gedeelte van een functie invult en dat je dan een functie terugkrijgt waarbij de overige argumenten nog kunnen worden ingevuld.
Dat klinkt heel moeilijk, dus laat ik maar snel een voorbeeldje geven:
Wat we hier doen is een functie maken die van implode het eerste argument op ' ' instelt. We hebben dan dus eigenlijk implode(' ', ???). Vervolgens roepen we die functie aan met een array die op de plek van die vraagtekens komt, we krijgen dan dus implode(' ', array(...)) en dat wordt vervolgens uitgevoerd.
We kunnen dit ook met operators gebruiken, dan moeten we ze alleen wel even omzetten in een functie met de operator functie:
Hier maken we dus een functie ??? * 2 die we vervolgens aanroepen met 10, wat resulteert in 10 * 2 = 20.
Waarom is dit handig? zul je je afvragen. Nou, neem eens een simpele array filter actie:
Merk op dat de volgende van de argumenten uitmaakt: curry(callable, argument) maakt een functie waarbij argument 1 onbekend is. En curry(argument, callable) maakt een functie waarbij argument 2 onbekend is.
Lazy loading
De library heeft ook heel veel functies die niks anders doen dan iterator over iterator heen plakken. Hierdoor krijg je een lazy loading effect, de volgende waarde wordt pas opgehaald wanneer daar om gevraagd wordt.
Begin je bijvoorbeeld eerst met 200 items en stop je in de loop al naar 10 items, dan worden er maar 10 items opgevraagd ipv 200, als je een array gebruikt is dit niet het geval.
Er zijn 2 manieren om lazy loading te beginnen: een range van getallen opstellen met range of een eigen lazy iterator initialiseren.
We bespreken hier alleen de eerste methode. De range functie heeft een begin en eind en zal daartussen lopen doormiddel van de lazy SuccessiveIterator:
Door 1 stap voor te doen kun je de stapgrootte aangeven:
Merk op dat je voor een negatieve stapgrootte altijd de stap moet geven: range(1, 0, -10).
Deze iterator kunnen we vervolgens in elke andere iterator stoppen. De library komt hiervoor met 4 functies: (callbable is een functie (kan currying zijn) en traversable is de iterator)
map(callable, traversable)
Deze zal de callable voor elke waarde van de iterator aanroepen (wanneer hier om gevraagd wordt uiteraard):
reduce(callable, traversable, accumulator = null)
Deze functie zal de iterator terugbrengen tot 1 waarde. De callable returnd de waarde voor de volgende functie, de accumulator is de start waarde.
filter(callable, traversable)
Deze plaatst de iterator in een CallbackFilterIterator:
takeWhile(callable, traversable)
Deze pakt alle elementen totdat de callable false returned:
2
3
4
5
6
7
8
9
use Wj\fn as f;
var_dump(f\takeWhile(
f\curry(f\operator('<'), 10),
f\to_iterator(1, 2, 3, 4, 20, 5, 6, 7, 8, 9)
));
//> Array(1, 2, 3, 4)
?>
Lazy loading in de praktijk
Wanneer gebruiken we lazy loading nou in de praktijk? Het mooie is dat we nu zonder zorgen Infinity (INF in php) kunnen gebruiken, als we maar een takeWhile erin stoppen of als we maar de loop zelf een keer stoppen.
Een vraagstuk als: Hoeveel kwadraten onder de 200 zijn er? Kunnen we op deze manier simpel oplossen.
Eerst maken we een range van 1 tot oneindig:
Vervolgens nemen we van de opgevraagde elementen uit deze lijst de kwadraten:
En daarna pakken we ze totdat we de 200 overschrijden:
2
3
4
5
6
7
8
9
10
11
use Wj\fn as f;
f\takeWhile(
f\curry(f\operator('<='), 200),
f\map(
f\curry(f\operator('^'), 2),
f\range(1, INF)
)
);
?>
En als laatst converteren we dit tot een array en tellen we het aantal elementen:
Het antwoord is 14!
Met dank aan
Deze library is geïnspireerd door Haskell en nikic/iter (die dit op een PHP 5.5+ manier aanpakt).
Voor de geïnteresseerden, in haskell zou het bovenstaande voorbeeld er zo uitzien:
Gesponsorde koppelingen
PHP script bestanden
Er zijn 5 reacties op 'Fn lazy loading currying etc'
Om te reageren heb je een account nodig en je moet ingelogd zijn.
PHP hulp
0 seconden vanaf nu