Μια γρήγορη εισαγωγή στο σωληνάριο () και τη σύνταξη () σε JavaScript

Ο λειτουργικός προγραμματισμός ήταν ένα αρκετά ανοιχτό ταξίδι για μένα. Αυτή η ανάρτηση, και δημοσιεύσεις σαν αυτήν, είναι μια προσπάθεια να μοιραστώ τις ιδέες και τις προοπτικές μου καθώς ταξιδεύω σε νέα λειτουργικά προγράμματα.

Η Ramda ήταν η βιβλιοθήκη FP μου, γιατί είναι πολύ πιο εύκολο να κάνει λειτουργικό προγραμματισμό σε JavaScript. Το συνιστώ ανεπιφύλακτα.

Σωλήνας

Η έννοια του pipeείναι απλή - συνδυάζει nλειτουργίες. Είναι ένας σωλήνας που ρέει αριστερά προς τα δεξιά, καλεί κάθε λειτουργία με την έξοδο της τελευταίας.

Ας γράψουμε μια συνάρτηση που επιστρέφει κάποιον name.

getName = (person) => person.name; getName({ name: 'Buckethead' }); // 'Buckethead' 

Ας γράψουμε μια συνάρτηση που είναι κεφαλαία.

uppercase = (string) => string.toUpperCase(); uppercase('Buckethead'); // 'BUCKETHEAD' 

Έτσι, αν θέλαμε να πάρουμε και να κεφαλαιοποιήσουμε personτο όνομα, θα μπορούσαμε να το κάνουμε:

name = getName({ name: 'Buckethead' }); uppercase(name); // 'BUCKETHEAD' 

Αυτό είναι εντάξει, αλλά ας εξαλείψουμε αυτήν την ενδιάμεση μεταβλητή name.

uppercase(getName({ name: 'Buckethead' })); 

Καλύτερα, αλλά δεν μου αρέσει αυτή η φωλιά. Μπορεί να είναι πολύ γεμάτο. Τι γίνεται αν θέλουμε να προσθέσουμε μια συνάρτηση που λαμβάνει τους πρώτους 6 χαρακτήρες μιας συμβολοσειράς;

get6Characters = (string) => string.substring(0, 6); get6Characters('Buckethead'); // 'Bucket' 

Εχοντας ως αποτέλεσμα:

get6Characters(uppercase(getName({ name: 'Buckethead' }))); // 'BUCKET'; 

Ας πάμε πραγματικά τρελοί και προσθέστε μια λειτουργία για να αντιστρέψετε τις χορδές.

reverse = (string) => string .split('') .reverse() .join(''); reverse('Buckethead'); // 'daehtekcuB' 

Τώρα έχουμε:

reverse(get6Characters(uppercase(getName({ name: 'Buckethead' })))); // 'TEKCUB' 

Μπορεί να πάρει λίγο… πολύ.

Σωλήνας για τη διάσωση!

Αντί να μπλοκάρει συναρτήσεις μέσα σε συναρτήσεις ή να δημιουργεί μια δέσμη ενδιάμεσων μεταβλητών, ας κάνουμε pipeόλα!

pipe( getName, uppercase, get6Characters, reverse )({ name: 'Buckethead' }); // 'TEKCUB' 

Καθαρή τέχνη. Είναι σαν μια λίστα υποχρεώσεων!

Ας το περάσουμε.

Για σκοπούς επίδειξης, θα χρησιμοποιήσω μια pipeεφαρμογή από ένα από τα άρθρα λειτουργικού προγραμματισμού του Eric Elliott.

pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x); 

Λατρεύω αυτό το μικρό σκάφος.

Χρησιμοποιώντας παραμέτρους ανάπαυσης , δείτε το άρθρο μου σχετικά με αυτό, μπορούμε να κάνουμε σωληνώσεις n. Κάθε συνάρτηση λαμβάνει την έξοδο της προηγούμενης και μειώνεται ; σε μία τιμή.

Και μπορείτε να το χρησιμοποιήσετε όπως κάναμε παραπάνω.

pipe( getName, uppercase, get6Characters, reverse )({ name: 'Buckethead' }); // 'TEKCUB' 

Θα επεκτείνω pipeκαι θα προσθέσω κάποιες δηλώσεις εντοπισμού σφαλμάτων και θα ακολουθούμε κάθε γραμμή

pipe = (...functions) => (value) => { debugger; return functions.reduce((currentValue, currentFunction) => { debugger; return currentFunction(currentValue); }, value); }; 

Καλέστε pipeμε το παράδειγμά μας και αφήστε τα θαύματα να ξεδιπλωθούν.

Ελέγξτε τις τοπικές μεταβλητές. functionsείναι ένας πίνακας από τις 4 συναρτήσεις και valueείναι { name: 'Buckethead' }.

Εφόσον χρησιμοποιήσαμε παραμέτρους ανάπαυσης , pipeεπιτρέπει τη χρήση οποιουδήποτε αριθμού λειτουργιών. Θα βγει απλώς και θα καλέσει το καθένα.

Στο επόμενο πρόγραμμα εντοπισμού σφαλμάτων, είμαστε μέσα reduce. Αυτό είναι το σημείο currentValueπου μεταφέρεται currentFunctionκαι επιστρέφεται.

Βλέπουμε το αποτέλεσμα 'Buckethead'γιατί currentFunctionεπιστρέφει την .nameιδιότητα οποιουδήποτε αντικειμένου. Αυτό θα επιστραφεί reduce, που σημαίνει ότι θα γίνει το νέο την currentValueεπόμενη φορά. Ας πατήσουμε το επόμενο πρόγραμμα εντοπισμού σφαλμάτων και να δούμε.

Τώρα currentValueείναι ‘Buckethead’γιατί αυτό επέστρεψε την τελευταία φορά. currentFunctionείναι uppercase, έτσι 'BUCKETHEAD'θα είναι το επόμενο currentValue.

Η ίδια ιδέα, αποσπάστε ‘BUCKETHEAD’τους πρώτους 6 χαρακτήρες και παραδώστε τους στην επόμενη λειτουργία.

reverse(‘.aedi emaS’)

Και τελειώσατε!

Τι γίνεται με τη σύνθεση ();

Είναι ακριβώς pipeπρος την άλλη κατεύθυνση.

Αν θέλετε το ίδιο αποτέλεσμα με τα pipeπαραπάνω, θα κάνατε το αντίθετο.

compose( reverse, get6Characters, uppercase, getName )({ name: 'Buckethead' }); 

Παρατηρήστε πώς getNameείναι το τελευταίο στην αλυσίδα και reverseείναι το πρώτο;

Ακολουθεί μια γρήγορη εφαρμογή compose, για άλλη μια φορά, του Magical Eric Elliott, από το ίδιο άρθρο.

compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x); 

Θα αφήσω να επεκτείνω αυτήν τη λειτουργία με το debuggers ως ​​άσκηση σε εσάς. Παίξτε μαζί του, χρησιμοποιήστε το, εκτιμήστε το. Και το πιο σημαντικό, διασκεδάστε!