Νιάου! Ξεκινήστε να χρησιμοποιείτε τις Γάτες στο έργο σας τώρα

Απαλή εισαγωγή στη βιβλιοθήκη Cats.

Εισαγωγή

Οι γάτες είναι μια βιβλιοθήκη που παρέχει αφαιρέσεις για λειτουργικό προγραμματισμό στη Σκάλα.

Υπάρχουν μερικές σπουδαίες δημοσιεύσεις και μαθήματα σχετικά με τις γάτες εκεί έξω στο διαδίκτυο (όπως οι γάτες Herding και ένα σεμινάριο για τις ασκήσεις Scala), αλλά έχουν την τάση να εξερευνούν τις κατηγορίες / τάξεις που εφαρμόζονται στη βιβλιοθήκη αντί να δίνουν πρακτικές έτοιμες προς χρήση χρησιμοποιήστε παραδείγματα για τον τρόπο χρήσης των Γάτων σε υπάρχουσες κωδικές βάσεις. Αυτή η ανάρτηση ιστολογίου μόλις γρατζουνίζει την επιφάνεια όσων μπορούν να κάνουν οι Γάτες, αλλά παρέχει μια συνοπτική, πρακτική εισαγωγή στα πρότυπα που είναι πιο πιθανό να επωφεληθούν από το σχέδιο Scala. Αν χρησιμοποιείτε καθημερινά τυχόν monads όπως Future ή Option, είναι πολύ πιθανό οι Γάτες να απλοποιήσουν και να βελτιώσουν την αναγνωσιμότητα του κώδικα σας.

Ανατρέξτε στο wiki Cats στο GitHub για οδηγίες σχετικά με τον τρόπο προσθήκης της βιβλιοθήκης στις εξαρτήσεις του έργου σας. Είμαστε κολλημένοι στην έκδοση 0.9.0 σε ολόκληρη τη θέση.

Ας δούμε την πακέτα βιβλιοθήκης, εξετάζοντας τη σύνταξη που είναι διαθέσιμη σε κάθε πακέτο.

Βοηθοί για την επιλογή και οπουδήποτε

εισαγωγή cats.syntax.option._

Η εισαγωγή αυτού του πακέτου επιτρέπει τη σύνταξη σύνθετου συμβόλου - ισοδύναμη με κάποια (obj). Η μόνη πραγματική διαφορά είναι ότι η τιμή είναι ήδη upcast στην επιλογή [T] από μερικές [T].

Χρησιμοποιώντας το obj.some αντί για κάποιο (obj) μπορεί μερικές φορές να βελτιωθεί η αναγνωσιμότητα των δοκιμών μονάδας. Για παράδειγμα, εάν προσθέσετε την ακόλουθη έμμεση κλάση στο BaseSpec, το TestHelper ή σε οποιαδήποτε κλάση βάσης για τις δοκιμές καλείται:

τότε μπορείτε να χρησιμοποιήσετε την αλυσοδεμένη σύνταξη που φαίνεται παρακάτω (αν υποτεθεί ότι οι δοκιμές της μονάδας σας βασίζονται στο scalamock, δείτε επίσης μια θέση του Bartosz Kowalik):

Αυτό είναι πιο ευανάγνωστο από το Future.successful (Μερικοί (χρήστης)), ειδικά εάν αυτό το πρότυπο επαναλαμβάνεται συχνά στη δοκιμαστική σουίτα. Η αλυσιδωτή αντίδραση στο τέλος και όχι η τοποθέτησή του στο μπροστινό μέρος βοηθά επίσης να εστιάσετε σε αυτό που πραγματικά επιστρέφεται και όχι στον αναμενόμενο τύπο περιτυλίγματος.

κανένα [T], με τη σειρά του, είναι συντομογραφία για Option.empty [T] που είναι απλά Κανένα, αλλά ήδη upcast από την επιλογή None.typeto [T]. Η παροχή ενός πιο εξειδικευμένου τύπου βοηθά μερικές φορές τον μεταγλωττιστή Scala να συνάγει σωστά τον τύπο των εκφράσεων που περιέχουν None.

εισαγωγή cats.syntax.either._

obj.asRight είναι δεξιά (obj), obj.asLeft αριστερά (obj). Και στις δύο περιπτώσεις ο τύπος της επιστρεφόμενης τιμής διευρύνεται από τη Δεξιά ή την Αριστερή στην Εσένα. Όπως ακριβώς συμβαίνει με τους .some, αυτοί οι βοηθοί είναι βολικοί για να συνδυαστούν με το .asfuture για να βελτιώσουν την αναγνωσιμότητα των τεστ μονάδας:

Είτε από την επιλογή (επιλογή: επιλογή [Α], ανName: => E), με τη σειρά της, είναι ένας χρήσιμος βοηθός για τη μετατροπή μιας επιλογής σε ένα από τα δύο. Εάν η παρεχόμενη επιλογή είναι Μερικές (x), γίνεται Δεξιά (x). Διαφορετικά γίνεται Αριστερά με την παρεχόμενη τιμή ifNone μέσα.

πακέτα περιπτώσεων και καρτεσιανή σύνταξη

εισαγάγετε στιγμιότυπα. .

Υπάρχουν μερικές τάξεις τύπου που είναι θεμελιώδεις για τις Γάτες (και γενικά για τον λειτουργικό προγραμματισμό με βάση την κατηγορία), οι σημαντικότεροι από τους οποίους είναι οι Functor, Applicative και Monad. Δεν πρόκειται να κάνουμε πολλές λεπτομέρειες σε αυτήν την ανάρτηση ιστολογίου (βλ. Π.χ. το ήδη αναφερθέν εκπαιδευτικό πρόγραμμα), αλλά αυτό που είναι σημαντικό να γνωρίζουμε είναι ότι για να χρησιμοποιήσετε τη σύνταξη των περισσότερων Cats, πρέπει επίσης να εισαγάγετε τις εμφανίσεις κλάσης σιωπηρού τύπου για τις δομές που " λειτουργούν με.

Συνήθως, αρκεί να εισάγετε το κατάλληλο πακέτο cats.instances. Για παράδειγμα, όταν κάνετε τις μετατροπές σε συμβόλαια μελλοντικής εκπλήρωσης, θα χρειαστεί να εισαγάγετε cats.instances.future._. Τα αντίστοιχα πακέτα για επιλογές και λίστες καλούνται cats.instances.option._ και cats.instances.list._. Παρέχουν τις υποδείξεις κλάσης σιωπηρού τύπου που χρειάζεται η σύνταξη των Cats να λειτουργεί σωστά.

Ως πλάγια σημείωση, αν έχετε πρόβλημα στην εύρεση της απαιτούμενης παρουσίας ή σύνταξης πακέτου, ο γρήγορος τρόπος αντιμετώπισης είναι να εισαγάγετε μόνο τα cats.implicits._. Αυτό όμως δεν είναι μια προτιμώμενη λύση, καθώς μπορεί να αυξήσει σημαντικά τον χρόνο σύνταξης - ειδικά εάν χρησιμοποιείται σε πολλά αρχεία σε όλο το έργο. Θεωρείται γενικά καλή πρακτική η χρήση στενών εισαγωγών για να ληφθεί μέρος του έμμεσου φορτίου επίλυσης από τον μεταγλωττιστή.

εισαγωγή cats.syntax.cartesian._

Το καρτεσιανό πακέτο παρέχει | @ | σύνταξη, η οποία επιτρέπει μια διαισθητική κατασκευή για την εφαρμογή μιας συνάρτησης που απαιτεί περισσότερες από μία παραμέτρους σε πολλαπλές πραγματικές τιμές (όπως τα συμβόλαια μελλοντικής εκπλήρωσης).

Ας υποθέσουμε ότι έχουμε 3 συμβόλαια μελλοντικής εκπλήρωσης, έναν τύπο Int, έναν τύπο String, έναν τύπο χρήστη και μια μέθοδο που δέχεται τρεις παραμέτρους - Int, String και User.

Στόχος μας είναι να εφαρμόσουμε τη λειτουργία στις αξίες που υπολογίζονται από αυτά τα 3 συμβόλαια μελλοντικής εκπλήρωσης. Με την καρτεσιανή σύνταξη γίνεται πολύ εύκολη και συνοπτική:

Όπως επισημάνθηκε προηγουμένως, για να παράσχει το σιωπηρό παράδειγμα (δηλαδή, Καρτεσιανό [Μελλοντικό]) που απαιτείται για | @ | για να λειτουργήσει σωστά, θα πρέπει να εισαγάγετε cats.instances.future._.

Αυτή η παραπάνω ιδέα μπορεί να εκφραστεί ακόμη μικρότερη, μόνο:

Το αποτέλεσμα της παραπάνω έκφρασης θα είναι τύπου Future [ProcessingResult]. Αν κάποιο από τα αλυσιδωτά συμβόλαια μελλοντικής εκπλήρωσης αποτύχει, το μελλοντικό μέλλον θα αποτύχει επίσης με την ίδια εξαίρεση με το πρώτο αποτυχημένο μέλλον στην αλυσίδα (αυτή είναι η γρήγορη συμπεριφορά). Αυτό που είναι σημαντικό, όλα τα συμβόλαια θα λειτουργούν παράλληλα, σε αντίθεση με αυτό που θα συμβεί σε μια αντίληψη:

Στο παραπάνω απόσπασμα (το οποίο κάτω από την κουκούλα μεταφράζεται σε κλήσεις flatMap και χαρτών), το stringFuture δεν θα τρέξει μέχρι να ολοκληρωθεί με επιτυχία το intFuture και με τον ίδιο τρόπο το userFuture θα εκτελεστεί μόνο μετά την ολοκλήρωση του stringFuture. Αλλά επειδή οι υπολογισμοί είναι ανεξάρτητοι μεταξύ τους, είναι τελείως βιώσιμο να τρέχουν παράλληλα με | @ | αντι αυτου.

Τράβηγμα

εισαγωγή cats.syntax.traverse._

διασχίζω

Εάν έχετε μια εντολή obj του τύπου F [A] που μπορεί να χαρτογραφηθεί (όπως Future) και μια διασκέδαση λειτουργίας τύπου A => G [B], τότε η κλήση obj.map (διασκέδαση) θα σας δώσει F [G [ ΣΙ]]. Σε πολλές κοινές περιπτώσεις πραγματικής ζωής, όπως όταν το F είναι Επιλογή και το G είναι το μέλλον, θα έχετε την επιλογή [Future [B]], η οποία κατά πάσα πιθανότητα δεν είναι αυτό που ήθελε.

η μετάβαση έρχεται ως λύση εδώ. Εάν ονομάζετε traverse αντί του χάρτη, όπως το obj.traverse (διασκέδαση), θα πάρετε το G [F [A]], το οποίο θα είναι μελλοντικό [Option [B]] στην περίπτωσή μας. αυτό είναι πολύ πιο χρήσιμο και πιο εύκολο στη διαδικασία από την επιλογή [Future [B]].

Ως δευτερεύουσα σημείωση, υπάρχει επίσης μια αφοσιωμένη μέθοδος Future.traverse στο μελλοντικό αντικείμενο σύντροφο, αλλά η έκδοση Cats είναι πολύ πιο ευανάγνωστη και μπορεί εύκολα να λειτουργήσει σε οποιαδήποτε δομή για την οποία είναι διαθέσιμες ορισμένες κατηγορίες τύπων.

αλληλουχία

Η ακολουθία αντιπροσωπεύει μια ακόμη απλούστερη έννοια: μπορεί να θεωρηθεί ως απλή εναλλαγή των τύπων από F [G [A]] σε G [F [A]] χωρίς να χαρτογραφηθεί η κλειστή τιμή όπως η traverse does.

Το obj.sequence υλοποιείται στην Cats ως obj.traverse (ταυτότητα). Από την άλλη πλευρά, το obj.traverse (διασκέδαση) είναι περίπου ισοδύναμο με το obj.map (fun) .sequence.

flatTraverse

Αν έχετε ένα obj του τύπου F [A] και ένα fun fun του τύπου A => G [F [B]], τότε κάνοντας obj.map (f) αποδίδει το αποτέλεσμα του τύπου F [G [F [B] - πολύ απίθανο να είναι αυτό που ήθελες.

Η μετακίνηση του obj αντί του χαρτογράφησης βοηθά λίγο - θα πάρετε αντί να [G [F [B]]. Δεδομένου ότι το G είναι συνήθως κάτι σαν το μέλλον και το F είναι λίστα ή επιλογή, θα καταλήγετε στο Future [Option [Option]] ή Future [Λίστα [A]]] - λίγο δύσκολο να το επεξεργαστείτε.

Η λύση θα μπορούσε να είναι η χαρτογράφηση του αποτελέσματος με μια κλήση _.flatten όπως:

και με αυτόν τον τρόπο θα έχετε τον επιθυμητό τύπο G [F [B]] στο τέλος.

Ωστόσο, υπάρχει μια ταχεία συντόμευση για αυτό που ονομάζεται flatTraverse:

και αυτό λύει το πρόβλημά μας για πάντα.

Μοναδικοί μετασχηματιστές

εισαγωγή cats.data.OptionT

Μια παράμετρος της OptionT [F, A] μπορεί να θεωρηθεί ως περιτύλιγμα πάνω από το F [Option [A]], το οποίο προσθέτει μερικές χρήσιμες μεθόδους ειδικά για τους ένθετους τύπους που δεν είναι διαθέσιμοι στο F ή στην ίδια την επιλογή. Πιο συνηθισμένα, ο F σας θα είναι μέλλον (ή μερικές φορές slick's DBIO, αλλά αυτό απαιτεί την εφαρμογή κατηγοριών τύπου Cats όπως Functor ή Monad για DBIO). Τα περιτυλίγματα όπως το OptionT είναι γενικά γνωστά ως μετασχηματιστές monad.

Ένα αρκετά κοινό πρότυπο είναι η χαρτογράφηση της εσωτερικής τιμής που είναι αποθηκευμένη μέσα σε μια εμφάνιση του F [Option [A]] σε μια περίπτωση του F [Option [B]] με μια συνάρτηση τύπου A => B. Αυτό μπορεί να γίνει με μάλλον λεπτομερή σύνταξη σαν:

Με τη χρήση του OptionT, αυτό μπορεί να απλουστευθεί ως εξής:

Ο παραπάνω χάρτης επιστρέφει μια τιμή του τύπου OptionT [Future, String].

Για να πάρετε την υποκείμενη μελλοντική τιμή [Option [String]], απλά καλέστε την .value στην επιλογή OptionT. Είναι επίσης μια βιώσιμη λύση για την πλήρη μετάβαση στην επιλογήT [Future, A] στις παραμέτρους μεθόδου / τύπους επιστροφής και εντελώς (ή σχεδόν τελείως) το μέλλον Future [Option [A]] σε δηλώσεις τύπου.

Υπάρχουν διάφοροι τρόποι για να δημιουργηθεί μια παράμετρο OptionT. Οι κεφαλίδες μεθόδου στον παρακάτω πίνακα είναι ελαφρώς απλοποιημένες: παραλείπονται οι παράμετροι τύπου και οι κατηγορίες τύπων που απαιτούνται από κάθε μέθοδο.

Στον κώδικα παραγωγής θα χρησιμοποιείτε συνηθέστερα τη σύνταξη OptionT (...) για να τυλίξετε μια εμφάνιση του μέλλοντος [Option [A]] στην επιλογή [F, A]. Οι άλλες μέθοδοι, με τη σειρά τους, αποδεικνύονται χρήσιμες για τη ρύθμιση των τυποποιημένων τιμών OptionT σε δοκιμές μονάδων.

Έχουμε ήδη συναντήσει μία από τις μεθόδους του OptionT, δηλαδή τον χάρτη. Υπάρχουν πολλές άλλες διαθέσιμες μέθοδοι και διαφέρουν ως επί το πλείστον από την υπογραφή της συνάρτησης που δέχονται ως παράμετρο. Όπως και με τον προηγούμενο πίνακα, οι αναμενόμενες κατηγορίες τύπων παραβλέπονται.

Στην πράξη, είναι πιθανότερο να χρησιμοποιήσετε το χάρτη και το semiflatMap.

Όπως συμβαίνει πάντοτε με το flatmap και το χάρτη, μπορείτε να το χρησιμοποιήσετε όχι μόνο ρητά, αλλά και κάτω από την κουκούλα σε παραστάσεις, όπως στο παρακάτω παράδειγμα:

Η παράμετρο OptionT [Future, Money] που επιστρέφεται από το getReservedFundsForUser θα περικλείει μια μηδενική τιμή αν οποιαδήποτε από τις τρεις μεθόδους συνθέσει επιστρέφει μια επιλογήT που αντιστοιχεί σε καμία. Διαφορετικά, αν το αποτέλεσμα και των τριών κλήσεων περιέχει Μερικές, το τελικό αποτέλεσμα θα περιέχει επίσης Μερικές.

εισαγωγή cats.data.EitherT

EitherT [F, A, B] είναι ο μονοφασικός μετασχηματιστής για το either - μπορείτε να το σκεφτείτε σαν περιτύλιγμα πάνω από μια τιμή F [Είτε [A, B]].

Όπως και στην παραπάνω ενότητα, απλοποίησα τις κεφαλίδες μεθόδου, παρακάμπτοντας τις παραμέτρους τύπου ή τα όρια περιβάλλοντος και τα όρια.

Ας ρίξουμε μια γρήγορη ματιά στο πώς να δημιουργήσουμε ένα παράδειγμα EitherT:

Ακριβώς για να ξεκαθαρίσετε: Είτε από κάθε πλευρά περιτυλίγει την παρεχόμενη Ή σε F, ενώ EitherT.right και EitherT.left τυλίξτε την τιμή εντός του παρεχόμενου F προς τα δεξιά και προς τα αριστερά, αντίστοιχα. Το EitherT.pure, με τη σειρά του, περιτυλίγει την παρεχόμενη τιμή Β στο Right και έπειτα στο F.

Ένας άλλος χρήσιμος τρόπος για να δημιουργήσετε μια παράμετρο EitherT είναι να χρησιμοποιήσετε τις μεθόδους OptionT στοLeft και toRight:

toRight είναι αρκετά ανάλογη με τη μέθοδο AnyitherfromOption που αναφέρθηκε προηγουμένως: ακριβώς όπως από τοBuybuiltA είτε από μια επιλογή, toRight δημιουργεί ένα EitherT από OptionT. Εάν το αρχικό OptionTestores κάποια αξία, θα τυλιχτεί σε Δεξιά? διαφορετικά η τιμή που παρέχεται ως η αριστερή παράμετρος θα τυλιχτεί σε μια Αριστερά.

το toLeft είναι το αντίστοιχο τουRight, το οποίο περιτυλίγει την ορισμένη τιμή στην Αριστερά και μετασχηματίζει Καμία σε Rightenclosing της παρεχόμενης σωστής τιμής. Αυτό χρησιμοποιείται λιγότερο στην πράξη, αλλά μπορεί να εξυπηρετεί π.χ. για την επιβολή ελέγχων μοναδικότητας στον κώδικα. Επιστρέφουμε αριστερά αν έχει βρεθεί η τιμή και δεξιά εάν δεν υπάρχει ακόμα στο σύστημα.

Οι διαθέσιμες μέθοδοι στο EitherT είναι παρόμοιες με αυτές που έχουμε δει στην OptionT, αλλά υπάρχουν κάποιες αξιοσημείωτες διαφορές. Ενδεχομένως να εμφανιστεί κάποια σύγχυση στην αρχή όταν πρόκειται για π.χ. χάρτης. Στην περίπτωση της OptionT, ήταν αρκετά προφανές τι πρέπει να γίνει: ο χάρτης θα πρέπει να μεταβεί στην Επιλογή που περιβάλλεται στο μέλλον και στη συνέχεια να χαρτογραφήσει την ίδια την Εφαρμοσμένη Επιλογή. Αυτό είναι ελαφρώς λιγότερο προφανές στην περίπτωση του EitherT: θα έπρεπε να χαρτογραφεί τις αξίες Leftand Right και μόνο τη σωστή τιμή;

Η απάντηση είναι ότι το EitherT είναι σωστά προκατειλημμένο, επομένως ο απλός χάρτης πραγματεύεται την σωστή τιμή. Αυτό είναι αντίθετο είτε με την τυπική βιβλιοθήκη Scala μέχρι 2.11, η οποία με τη σειρά της είναι αμερόληπτη: δεν υπάρχει κανένας διαθέσιμος χάρτης στο Any, μόνο για τις αριστερές και τις σωστές προβολές.

Τούτου λεχθέντος, ας ρίξουμε μια γρήγορη ματιά στις σωστά μεροληπτικές μεθόδους που EitherT [F, A, B] προσφέρει:

Ως πλάγια σημείωση υπάρχουν επίσης ορισμένες μέθοδοι στο EitherT (που πιθανότατα θα χρειαστείτε σε κάποιο σημείο) οι οποίες χαρτογραφούν πάνω από την Αριστερή τιμή, όπως leftMap ή πάνω από τις αξίες Αριστεράς και Δεξιάς, όπως το fold ή το bimap.

Το EitherT είναι πολύ χρήσιμο για επαληθεύσεις με αλυσιδωτές αποτυχίες:

Στο παραπάνω παράδειγμα, πραγματοποιούμε διάφορες επιταγές κατά του στοιχείου ένα προς ένα. Εάν κάποιος από τους ελέγχους αποτύχει, η προκύπτουσα EitherT θα περιέχει μια Αριστερή τιμή. Διαφορετικά, εάν όλοι οι έλεγχοι δίνουν ένα Δικαίωμα (φυσικά εννοούμε ένα Δικαίωμα που τυλίγεται σε ένα EitherT), τότε το τελικό αποτέλεσμα θα περιέχει επίσης Δικαίωμα. Αυτή είναι μια συμπεριφορά που αποτυγχάνει γρήγορα: σταματάμε αποτελεσματικά τη ροή κατανόησης στο πρώτο αριστερό αποτέλεσμα.

Αν αντίθετα ψάχνετε για επικύρωση που συσσωρεύει τα σφάλματα (π.χ. όταν ασχολείστε με τα δεδομένα φόρμας που παρέχονται από το χρήστη), το cats.data.Validated μπορεί να είναι μια καλή επιλογή.

Κοινά θέματα

Αν κάτι δεν μεταγλωττίσει όπως αναμενόταν, βεβαιωθείτε πρώτα ότι όλες οι απαιτούμενες προδιαγραφές Cats βρίσκονται στο πεδίο - απλά προσπαθήστε να εισαγάγετε cats.implicits._ και δείτε εάν το πρόβλημα παραμένει. Όπως αναφέρθηκε προηγουμένως, είναι καλύτερο να χρησιμοποιείτε στενές εισαγωγές, αλλά αν ο κώδικας δεν μεταγλωττίζει, μερικές φορές αξίζει να εισάγουμε ολόκληρη τη βιβλιοθήκη για να ελέγξουμε αν λύνει το πρόβλημα.

Εάν χρησιμοποιείτε Futures, φροντίστε να δώσετε ένα σιωπηλό ExecutionContext στο πεδίο εφαρμογής, διαφορετικά οι Cats δεν θα μπορούν να συμπεράνουν τις σιωπηρές παρουσίες για τις κλάσεις τύπου Future.

Ο μεταγλωττιστής μπορεί συχνά να έχει προβλήματα με την εξαγωγή παραμέτρων τύπου για μεθόδους μετατόπισης και ακολουθίας. Μια προφανής λύση είναι να προσδιοριστούν αυτοί οι τύποι άμεσα, όπως το list.traverse [Future, Unit] (διασκέδαση). Εν τούτοις, σε ορισμένες περιπτώσεις, μπορεί να γίνει αρκετά λεπτομερής, και ο καλύτερος τρόπος είναι να δοκιμάσετε τις αντίστοιχες μεθόδους traverseU και sequenceU, όπως το list.traverseU (διασκέδαση). Πραγματοποιούν κάποια τεχνάσματα (με cats.Unapply, εξ ου και το U) για να βοηθήσουν τον compiler να συμπεράνει τις παραμέτρους του τύπου.

Το IntelliJ αναφέρει μερικές φορές σφάλματα στον κώδικα που έχει φορτωθεί με γάτες, παρόλο που η πηγή περνά κάτω από το scalac. Ένα τέτοιο παράδειγμα είναι οι επικλήσεις των μεθόδων της κατηγορίας cats.data.Nested, οι οποίες συντάσσονται σωστά κάτω από το scalac, αλλά δεν πληκτρολογούν τον έλεγχο κάτω από τον μεταγλωττιστή παρουσίασης IntelliJ. Θα πρέπει να λειτουργεί χωρίς προβλήματα κάτω από το Scala IDE, όμως.

Ως συμβουλή για τη μελλοντική σας εκμάθηση: η κατηγορία εφαρμοστικού τύπου, παρά τη σημαντική σημασία της στον λειτουργικό προγραμματισμό, είναι λίγο δύσκολο να κατανοηθεί. Κατά τη γνώμη μου, είναι πολύ λιγότερο διαισθητικό από το Functor ή το Monad, αν και στην πραγματικότητα βρίσκεται ακριβώς μεταξύ Functor και Monad στην ιεραρχία κληρονομιάς. Η καλύτερη προσέγγιση για την κατανόηση της εφαρμογής είναι να καταλάβουμε πρώτα πώς το προϊόν (το οποίο μετατρέπει ένα F [A] και F [B] σε ένα F [(A, B)] λειτουργεί παρά να επικεντρώνεται στην ίδια κάπως εξωτική λειτουργία.