Σπίτι - Ρύθμιση Διαδικτύου
Τι είναι το όνομα συνάρτησης στον προγραμματισμό. Λειτουργίες προγραμματισμού

Στόχος της εργασίας: 1) μελετήστε τους κανόνες για την περιγραφή των συναρτήσεων. 2) αποκτούν δεξιότητες στη χρήση συναρτήσεων κατά τη σύνταξη προγραμμάτων σε C++.

Θεωρητικές πληροφορίες

Η κύρια ενότητα προγραμμάτων στη C++ είναι η συνάρτηση.

Λειτουργία- ένα λογικά ολοκληρωμένο, σίγουρα σχεδιασμένο τμήμα ενός προγράμματος που έχει όνομα. Οι συναρτήσεις σάς επιτρέπουν να διαιρέσετε μεγάλες υπολογιστικές εργασίες σε μικρότερες.

Κάθε πρόγραμμα C++ περιέχει απαραίτητα μια συνάρτηση που ονομάζεται main, η οποία είναι το σώμα του προγράμματος. Για όλες τις άλλες συναρτήσεις, εάν υπάρχουν στο πρόγραμμα, θα πρέπει να δηλωθούν πρωτότυπα - σχηματικές σημειώσεις που λένε στον μεταγλωττιστή το όνομα και τη μορφή κάθε συνάρτησης του προγράμματος.

Η σύνταξη για ένα πρωτότυπο συνάρτησης με παραμέτρους είναι:

return_value_type function_name (parameter_list_with_type_indication);

Οι συναρτήσεις στη C++ είναι τυπικές (βιβλιοθήκη) και μπορούν να προγραμματιστούν από το χρήστη.

Τυποποιημένα χαρακτηριστικά

Περιγραφές τυπικών συναρτήσεων βρίσκονται σε αρχεία που περιλαμβάνονται στο πρόγραμμα χρησιμοποιώντας την οδηγία #include. Τέτοια αρχεία ονομάζονται αρχεία κεφαλίδας. έχουν την προέκταση h.

Η αναφορά σε ένα όνομα συνάρτησης στο κύριο πρόγραμμα ονομάζεται κλήση συνάρτησης.

Η κλήση συναρτήσεων έχει ως αποτέλεσμα την εκτέλεση κάποιας ενέργειας ή τον υπολογισμό κάποιας τιμής, η οποία στη συνέχεια χρησιμοποιείται στο πρόγραμμα.

y = sin(x); //συνάρτηση υπολογισμού ημιτόνου

Ορισμός συνάρτησης

Γενικά, οι συναρτήσεις ορίζονται ως εξής:

return_value_type function_name (πληκτρολογήστε parameter_name,..., πληκτρολογήστε parameter_name)

body_function

Προγραμματιζόμενα χαρακτηριστικά

Οι λειτουργίες που δημιουργεί ο ίδιος ο προγραμματιστής απλοποιούν τη διαδικασία γραφής προγραμμάτων επειδή:

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

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

Παράδειγμα9 .1. Ας δημιουργήσουμε μια συνάρτηση που εκτυπώνει 65 χαρακτήρες "*" στη σειρά. Για να λειτουργήσει αυτή η λειτουργία σε κάποιο πλαίσιο, περιλαμβάνεται στο πρόγραμμα εκτύπωσης επιστολόχαρτων. Το πρόγραμμα αποτελείται από συναρτήσεις: main() και stars().

// Επιστολόχαρτο

#περιλαμβάνω

const int Limit=65;

void stars(void); // συνάρτηση πρωτότυπο αστέρια()

cout<<"Moscow Institute of Electronic Engineering"<

// Ορισμός της συνάρτησης stars().

για (count=1; count<=Limit; count++)

Εξετάσαμε ένα παράδειγμα μιας απλής συνάρτησης που δεν έχει ορίσματα και δεν επιστρέφει τιμές.

Παράμετροι συνάρτησης

Ας δούμε ένα παράδειγμα χρήσης παραμέτρων συνάρτησης.

Παράδειγμα9. 2. Ας γράψουμε τον χώρο συνάρτησης(), του οποίου το όρισμα θα είναι ο αριθμός των κενών που πρέπει να εκτυπώσει αυτή η συνάρτηση.

#define διεύθυνση "Zelenograd"

#define name "Moscow Institute Electronic Engineering"

#define τμήμα "Πληροφορική και Προγραμματισμός"

const int LIMIT=65;

#περιλαμβάνω

κενό διάστημα (αριθμός int);

cout<

spaces=(LIMIT - strlen(όνομα))/2; // Υπολογίστε πόσα

// χρειάζονται κενά

cout<

space((LIMIT - strlen(τμήμα))/2); // όρισμα - έκφραση

cout<

//Ορισμός της συνάρτησης stars().

για (count=1; count<=LIMIT; count++)

//Ορισμός της συνάρτησης space().

κενός χώρος (αριθμός int)

για (count=1; count<=number; count++)

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

Εάν μια συνάρτηση απαιτεί περισσότερα από ένα όρισμα για επικοινωνία, μπορείτε να καθορίσετε μια λίστα ορισμάτων διαχωρισμένων με κόμματα μαζί με το όνομα της συνάρτησης:

void printnum(int i, int j)

(cout<<"Координаты точек”<< i << j <

Η τιμή εισόδου της συνάρτησης μπορεί να υποβληθεί σε επεξεργασία λόγω της παρουσίας διαφωνία; Η τιμή εξόδου επιστρέφεται χρησιμοποιώντας τη λέξη-κλειδί επιστροφής.

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

Τι σημαίνουν οι όροι λειτουργία και διαδικασία;

  • Λειτουργίαστον προγραμματισμό, μια υπορουτίνα καλείται από άλλες υπορουτίνες τον απαιτούμενο αριθμό φορών.
  • Διαδικασία- ένα κατονομαζόμενο μέρος του προγράμματος (υπορουτίνα), επανειλημμένα καλούμενο από τα επόμενα μέρη του προγράμματος τον απαιτούμενο αριθμό φορών.

Σύγκριση λειτουργίας και διαδικασίας

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

Η κεφαλίδα συνάρτησης περιέχει τη λέξη "συνάρτηση", ένα αναγνωριστικό (το σωστό όνομα της συνάρτησης), προαιρετικά μια λίστα παραμέτρων και, απαραίτητα, τον τύπο του αποτελέσματος. Το σώμα της συνάρτησης πρέπει να περιέχει έναν τελεστή που εκχωρεί μια τιμή στο όνομα της συνάρτησης, την οποία θα επιστρέψει ως αποτέλεσμα. Η κεφαλίδα της διαδικασίας περιέχει τη λέξη «διαδικασία», ένα αναγνωριστικό (όνομα διαδικασίας) και προαιρετικά μια λίστα παραμέτρων.

Μια κλήση συνάρτησης πραγματοποιείται ως μέρος των παραστάσεων όπου χρησιμοποιούνται αυτές οι εκφράσεις· μια κλήση διαδικασίας απαιτεί ξεχωριστή δήλωση.

Μια διαδικασία καλείται μόνο με το όνομα, ενώ το όνομα μιας συνάρτησης σχετίζεται με την τιμή της. Στα διαγράμματα αλγορίθμων, μια κλήση συνάρτησης απεικονίζεται σε ένα μπλοκ εξόδου ή σε ένα μπλοκ διαδικασίας, μια κλήση διαδικασίας απεικονίζεται σε ένα ειδικό μπλοκ «προκαθορισμένης διεργασίας».

Η διαφορά μεταξύ μιας συνάρτησης και μιας διαδικασίας στον προγραμματισμό είναι η εξής:

  • Μια συνάρτηση επιστρέφει μια τιμή, μια διαδικασία όχι.
  • Η κεφαλίδα συνάρτησης πρέπει να περιέχει τον τύπο αποτελέσματος.
  • Το σώμα της συνάρτησης πρέπει να περιέχει μια δήλωση που εκχωρεί μια τιμή στο όνομα της συνάρτησης.
  • Η κλήση μιας διαδικασίας απαιτεί μια ξεχωριστή δήλωση· η κλήση μιας συνάρτησης είναι δυνατή ως μέρος μιας έκφρασης.
  • Το όνομα της διαδικασίας απαιτείται για να την καλέσετε, το όνομα της συνάρτησης απαιτείται για να εκχωρήσετε μια τιμή.
  • Στα διαγράμματα αλγορίθμων, μια κλήση διαδικασίας απεικονίζεται σε ξεχωριστό μπλοκ, μια κλήση συνάρτησης σε μια διεργασία ή μπλοκ εξόδου.

Η βάση κάθε προγράμματος υπολογιστή είναι οι αλγόριθμοι, που εκφράζονται ως εντολές. Το άτομο που γράφει τον κώδικα λέει, πάρε αυτό, κάνε αυτό, αυτό και εκείνο με αυτό, και μετά βγάλε το αποτέλεσμα εκεί και ξεκουράσου. Έτσι, ώστε οι εντολές στα προγράμματα να μην συγχωνεύονται σε ένα ενιαίο χάος και να μπορούν να αλληλεπιδρούν μεταξύ τους, ομαδοποιούνται στις λεγόμενες λειτουργίες και διαδικασίες. Θα εξοικειωθούμε με αυτές τις έννοιες.

Τι είναι συνάρτηση

Τα ονόματα συναρτήσεων χρησιμοποιούνται: 1) για τη δημιουργία τεκμηρίωσης. 2) για ένα API, δηλαδή μια διασύνδεση για σύνδεση με ένα πρόγραμμα ή ένα ολόκληρο λειτουργικό σύστημα οποιασδήποτε εφαρμογής. Επομένως, είναι λογικό να υπενθυμίσουμε για άλλη μια φορά ότι αυτά τα ονόματα πρέπει να δίνονται κατανοητά και, εάν είναι δυνατόν, κατάλληλα για τις ενέργειες που εκτελούνται.

Ας συνοψίσουμε

Έτσι, οι συναρτήσεις είναι ένα είδος δοχείων για την ομαδοποίηση αλγορίθμων. Αυτοί:

  1. υπεύθυνος για συγκεκριμένα καθήκοντα·
  2. αλληλεπιδρούν με άλλα αντικείμενα.
  3. αποτελούν την εννοιολογική βάση του σύγχρονου προγραμματισμού, όσο αξιολύπητο κι αν ακούγεται.

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

Προηγούμενες δημοσιεύσεις:

Δεν είναι τυχαίο που ονόμασα αυτό το άρθρο "Λειτουργίες ως αναπόσπαστο μέρος του προγραμματισμού", γιατί χωρίς αυτές, κατά τη γνώμη μου, καμία γλώσσα δεν έχει το δικαίωμα να υπάρχει. Τι είναι αυτό? Μια συνάρτηση είναι το κύριο συστατικό ενός καλογραμμένου προγράμματος. Όχι μόνο διευκολύνει την ανάγνωση του κώδικα, αλλά και αλλάζει ριζικά την ιδέα του δομημένου προγραμματισμού. Με τη βοήθεια συναρτήσεων, μπορείτε να επαναχρησιμοποιήσετε μεμονωμένα μέρη του προγράμματος μεταβιβάζοντάς τους οποιεσδήποτε παραμέτρους. Κανένα σοβαρό πρόγραμμα δεν μπορεί να φανταστεί κανείς χωρίς αυτό το θαύμα του στοιχείου προγραμματισμού.

Θα σας πω εν συντομία πώς λειτουργεί. Μια συνάρτηση είναι ένα μπλοκ εντολών που μπορεί να καλέσει το πρόγραμμά σας. Όταν γίνεται πρόσβαση στην κεφαλίδα αυτού του μπλοκ (όνομα συνάρτησης), εκτελείται και εκτελεί ορισμένες ενέργειες που καθορίζονται από τον προγραμματιστή. Μετά από αυτό, αυτό το μπλοκ επιστρέφει την τιμή που έλαβε και τη μεταβιβάζει στο κύριο πρόγραμμα. Επιτρέψτε μου να εξηγήσω στην πράξη.

Σε γενικές γραμμές, μοιάζει με αυτό. Επιτρέψτε μου να εξηγήσω εν συντομία. Δημιουργούμε κάποια μεταβλητή και της εκχωρούμε το αποτέλεσμα της εκτέλεσης της συνάρτησης myfunc, η οποία με τη σειρά της υπολογίζει την τιμή του τετραγωνισμού κάποιου αριθμού. Οι συναρτήσεις δεν εκτελούνται αμέσως όταν ξεκινά το πρόγραμμα, αλλά εκτελούνται μόνο όταν καλούνται. Μπορεί να είναι λίγο μπερδεμένο, αλλά έτσι είναι.

Πώς να καλέσετε μια συνάρτηση;

Για να καλέσετε μια συνάρτηση, πρέπει να τη δημιουργήσετε. Αν και υπάρχουν και ενσωματωμένες λειτουργίες. Για παράδειγμα αυτό: cos, sin, md5, count, absκαι ούτω καθεξής. Για να τα καλέσετε, πρέπει απλώς να αντιστοιχίσετε την επιθυμητή τιμή στη μεταβλητή.

Ένα όρισμα συνάρτησης είναι η τιμή που του μεταβιβάζετε όταν το καλείτε. Τα ορίσματα συνάρτησης τοποθετούνται σε παρένθεση. Όταν δημιουργείτε μια συνάρτηση, καθορίζετε ονόματα υπό όρους για τα ορίσματα. Στη συνέχεια, αυτά τα ονόματα μπορούν να χρησιμοποιηθούν στο σώμα της συνάρτησης, ως τοπικές μεταβλητές. Ας επιστρέψουμε στις λειτουργίες που δημιουργεί ο ίδιος ο χρήστης. Αυτό γίνεται πολύ εύκολα. Πρώτον, δημιουργείται το σώμα συνάρτησης:

Λειτουργία hello() ( echo "Hello, world!";)

Τότε της τηλεφωνούμε. Επιπλέον, αν δεν έχει παραμέτρους, τότε απλώς βάζουμε παρενθέσεις. Για να καλέσουμε αυτή τη συνάρτηση, χρησιμοποιούμε μόνο τη γραμμή: Γειά σου();. Οποιαδήποτε συνάρτηση μπορεί επίσης να επιστρέψει μια τιμή χρησιμοποιώντας μια δεσμευμένη λέξη ΕΠΙΣΤΡΟΦΗ. Αυτή η δήλωση σταματά την εκτέλεση της συνάρτησης και στέλνει την τιμή επιστροφής στο πρόγραμμα κλήσης. συνάρτηση sum($first, $second) ($r=$first + $second; return $r;) echo sum(2,5); το αποτέλεσμα της εκτέλεσης του προγράμματος θα είναι ίσο με 7. Τοπικές και καθολικές μεταβλητές

Όπως σε κάθε άλλη γλώσσα προγραμματισμού, υπάρχουν μεταβλητές που είναι διαθέσιμες μόνο μέσα σε μια συνάρτηση και μεταβλητές που είναι διαθέσιμες στον κώδικα του ίδιου του προγράμματος. Τέτοιες μεταβλητές ονομάζονται τοπικές και καθολικές, αντίστοιχα. Μέσα σε μια συνάρτηση, δεν μπορείτε απλά να έχετε πρόσβαση σε μια μεταβλητή που δημιουργήθηκε εκτός της συνάρτησης. Εάν προσπαθήσετε να το κάνετε αυτό, θα δημιουργήσετε μια νέα μεταβλητή με το ίδιο όνομα, αλλά τοπική σε αυτήν τη συνάρτηση.

$per="Dima"; function primer() // Εκτελεί: εμφάνιση τοπικής μεταβλητής ( echo "My name is ".$per; ) echo primer();

Σε αυτήν την περίπτωση, η φράση «Το όνομά μου είναι» θα εμφανιστεί στην οθόνη. Αυτό σημαίνει ότι η μεταβλητή $per δημιουργήθηκε μέσα στη συνάρτηση primer και της εκχωρήθηκε μια μηδενική τιμή από προεπιλογή. Για να αποφύγετε τέτοιου είδους εμπλοκές, πρέπει να χρησιμοποιήσετε τον χειριστή παγκόσμια. Ας διορθώσουμε τον παραπάνω κώδικα ανάλογα:

$per="Dima"; function primer() // Εκτελεί: εμφάνιση καθολικής μεταβλητής ( global $per; echo "My name is ".$per; ) echo primer();

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

Συναρτήσεις δύο ή περισσότερων ορισμάτων

Μερικά από τα ορίσματα που μεταβιβάζονται σε μια συνάρτηση μπορούν να γίνουν προαιρετικά, καθιστώντας τη συνάρτηση λιγότερο απαιτητική. Το παρακάτω παράδειγμα το δείχνει ξεκάθαρα:

… γραμματοσειρά συνάρτησης ($text, $size=5) // Do: μέγεθος γραμματοσειράς εξόδου ( echo " ".$text.""; ) font("Γεια
",1); γραμματοσειρά ("Γεια
",2); γραμματοσειρά ("Γεια
",3); γραμματοσειρά ("Γεια
",4); γραμματοσειρά ("Γεια
",5); γραμματοσειρά ("Γεια
",6); γραμματοσειρά ("Γεια
");

Από προεπιλογή, το μέγεθος της γραμματοσειράς είναι 5. Αν παραλείψουμε τη δεύτερη παράμετρο της συνάρτησης, θα είναι ίση με αυτήν την τιμή.

συμπέρασμα

Πριν σας αποχαιρετήσω, θέλω να επιστήσω την προσοχή σας σε μια συμβουλή. Αποτελείται από την τοποθέτηση όλων των συναρτήσεων που έχετε γράψει σε ένα αρχείο (για παράδειγμα, function.php). Και μετά, στο αρχείο όπου πρέπει να καλέσετε τη συνάρτηση, πρέπει απλώς να συμπεριλάβετε το function.php και όλα θα είναι έτοιμα για χρήση. Αυτό θα διευκολύνει πολύ την κατανόηση της λογικής του προγράμματός σας. Για να συνδεθείτε, χρησιμοποιήστε:

include_once("function.php");

require_once("function.php");

Εάν κατανοείτε την ουσία του ζητήματος που συζητείται σε αυτό το άρθρο, τότε είμαι σίγουρος ότι μπορείτε να χρησιμοποιήσετε εύκολα τις λειτουργίες στα προγράμματά σας. Για άλλη μια φορά, αυτό γίνεται για να γίνουν πιο προσαρμόσιμα και επαναχρησιμοποιήσιμα.

Αυτό είναι το τρίτο άρθρο της σειράς «Κατηγορία Θεωρία για Προγραμματιστές».

Ποιος χρειάζεται τύπους;

Υπάρχει κάποια διαφωνία στην κοινότητα σχετικά με τα οφέλη της στατικής έναντι της δυναμικής πληκτρολόγησης και της ισχυρής έναντι της ασθενούς πληκτρολόγησης. Επιτρέψτε μου να επεξηγήσω την επιλογή πληκτρολόγησης με ένα πείραμα σκέψης. Φανταστείτε εκατομμύρια μαϊμούδες με πληκτρολόγια, να πατούν χαρούμενα τυχαία πλήκτρα, να γράφουν, να μεταγλωττίζουν και να εκτελούν προγράμματα.

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

Το ερώτημα λοιπόν είναι, θέλουμε οι πίθηκοι να είναι χαρούμενοι ή να δημιουργούν σωστά προγράμματα;
(σημείωση του μεταφραστή: δεν χρειάζεται να προσβάλλεται, στον συγγραφέα απλώς αρέσουν λιγότερο βαρετές μεταφορές από το RNG και τις «τυχαίες ακολουθίες byte» και δεν αποκαλεί τους προγραμματιστές μαϊμούδες).

Τυπικά, ο στόχος του πειράματος σκέψης του πιθήκου δακτυλογράφησης είναι να δημιουργήσει τα πλήρη έργα του Σαίξπηρ (σημείωση του μεταφραστή: ή Πόλεμος και Ειρήνη του Τολστόι). Ο έλεγχος της ορθογραφίας και της γραμματικής σε έναν βρόχο θα αυξήσει δραματικά τις πιθανότητές σας για επιτυχία. Το ανάλογο ελέγχου τύπου προχωρά ακόμη παραπέρα: αφού ο Romeo δηλωθεί άνθρωπος, ο έλεγχος τύπου θα βεβαιωθεί ότι δεν θα φυτρώσει φύλλα και ότι δεν θα πιάσει φωτόνια με το ισχυρό βαρυτικό του πεδίο.

Απαιτούνται τύποι για συνθεσιμότητα

Η θεωρία των κατηγοριών μελετά τις συνθέσεις των βελών. Δεν μπορούν να συνδυαστούν μόνο δύο βέλη: το αντικείμενο-στόχος ενός βέλους πρέπει να ταιριάζει με το αντικείμενο προέλευσης του επόμενου. Στον προγραμματισμό περνάμε αποτελέσματα από τη μια συνάρτηση στην άλλη. Το πρόγραμμα δεν θα λειτουργήσει εάν η δεύτερη συνάρτηση δεν μπορεί να ερμηνεύσει σωστά τα δεδομένα που λαμβάνονται από την πρώτη. Και οι δύο λειτουργίες πρέπει να ταιριάζουν μεταξύ τους για να λειτουργήσει η σύνθεσή τους. Όσο ισχυρότερο είναι το σύστημα τύπων της γλώσσας, τόσο καλύτερα μπορεί να περιγραφεί και να επαληθευτεί αυτόματα αυτή η προσαρμογή.

Το μόνο σοβαρό επιχείρημα που ακούω ενάντια στην έντονη στατική πληκτρολόγηση είναι ότι μπορεί να απορρίψει ορισμένα προγράμματα που είναι σημασιολογικά σωστά. Στην πράξη αυτό συμβαίνει εξαιρετικά σπάνια (σημείωση μεταφραστή: για αποφυγή σύγχυσης, σημειώνω ότι ο συγγραφέας δεν έλαβε υπόψη ή δεν συμφωνεί, ότι υπάρχουν πολλά στυλ, και η πληκτρολόγηση πάπιας, η οποία είναι γνωστή στους προγραμματιστές σε γλώσσες σεναρίου, έχει επίσης δικαίωμα στη ζωή Από την άλλη πλευρά, η πληκτρολόγηση πάπιας είναι δυνατή σε σύστημα αυστηρού τύπου μέσω προτύπων, χαρακτηριστικών, κατηγοριών τύπων, διεπαφών, υπάρχουν πολλές τεχνολογίες, επομένως η γνώμη του συγγραφέα δεν μπορεί να θεωρηθεί αυστηρά εσφαλμένη.)και, σε κάθε περίπτωση, κάθε γλώσσα περιέχει κάποιο είδος κερκόπορτας για να παρακάμψει το σύστημα τύπων όταν είναι πραγματικά απαραίτητο. Ακόμη και ο Haskell έχει μη ασφαλή Coerce. Αλλά τέτοια σχέδια πρέπει να χρησιμοποιούνται με σύνεση. Ο χαρακτήρας του Φραντς Κάφκα Γκρέγκορ Σάμσα σπάει το σύστημα τύπων όταν μετατρέπεται σε γιγάντιο σκαθάρι και όλοι ξέρουμε πώς τελειώνει (σημείωση μεταφραστή: κακό :).

Ένα άλλο επιχείρημα που ακούω συχνά είναι ότι η έντονη πληκτρολόγηση επιβαρύνει πάρα πολύ τον προγραμματιστή. Μπορώ να συμφωνήσω με αυτό το πρόβλημα, αφού έχω γράψει ο ίδιος πολλές δηλώσεις επαναλήψεων στη C++, εκτός από το ότι υπάρχει μια τεχνολογία, συμπερασματικού τύπου, που επιτρέπει στον μεταγλωττιστή να συμπεράνει τους περισσότερους τύπους από το περιβάλλον στο οποίο χρησιμοποιούνται. Στη C++, μπορείτε να δηλώσετε μια μεταβλητή auto και ο μεταγλωττιστής θα συναγάγει τον τύπο για εσάς.

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

Η ισχυρή στατική πληκτρολόγηση χρησιμοποιείται συχνά ως δικαιολογία για τη μη δοκιμή του κώδικα. Μερικές φορές θα ακούσετε τους προγραμματιστές της Haskell να λένε, "Εάν ο κώδικας δημιουργείται, είναι σωστός". Φυσικά, δεν υπάρχει καμία εγγύηση ότι ένα πρόγραμμα που είναι σωστός τύπος είναι σωστό με την έννοια ότι παράγει το σωστό αποτέλεσμα. Ως αποτέλεσμα αυτής της στάσης, σε ορισμένες μελέτες ο Haskell δεν ξεπέρασε σημαντικά τις άλλες γλώσσες σε ποιότητα κώδικα, όπως θα περίμενε κανείς. Φαίνεται ότι σε ένα εμπορικό περιβάλλον η ανάγκη διόρθωσης σφαλμάτων υπάρχει μόνο μέχρι ένα ορισμένο επίπεδο ποιότητας, το οποίο σχετίζεται κυρίως με τα οικονομικά της ανάπτυξης λογισμικού και την ανοχή του τελικού χρήστη και έχει πολύ μικρή σχέση με τη γλώσσα προγραμματισμού ή την ανάπτυξη μεθοδολογία. Ένα καλύτερο μέτρο θα ήταν να μετρήσετε πόσα έργα καθυστερούν ή παραδίδονται με σημαντικά μειωμένη λειτουργικότητα.

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

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

Τι είναι οι τύποι;

Η απλούστερη περιγραφή των τύπων είναι ότι είναι σύνολα τιμών. Ο τύπος Bool (θυμηθείτε, οι τύποι σκυροδέματος ξεκινούν με κεφαλαίο γράμμα στο Haskell) αντιστοιχεί σε ένα σύνολο δύο στοιχείων: True και False. Ο τύπος Char είναι το σύνολο όλων των χαρακτήρων Unicode, όπως "a" ή "ą".

Τα σύνολα μπορεί να είναι πεπερασμένα ή άπειρα. Ο τύπος String, ο οποίος είναι ουσιαστικά συνώνυμο της λίστας Char, είναι ένα παράδειγμα ενός άπειρου συνόλου.

Όταν δηλώνουμε το x ως ακέραιο:
x::Ακέραιος αριθμός
λέμε ότι είναι στοιχείο του συνόλου των ακεραίων. Ο ακέραιος στο Haskell είναι ένα άπειρο σύνολο και μπορεί να χρησιμοποιηθεί για αριθμητική οποιασδήποτε ακρίβειας. Υπάρχει επίσης ένα πεπερασμένο σύνολο Int, το οποίο αντιστοιχεί σε έναν τύπο μηχανής, όπως το int στη C++.

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

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

Σε έναν ιδανικό κόσμο, θα μπορούσαμε απλά να πούμε ότι οι τύποι στο Haskell είναι σύνολα και οι συναρτήσεις στο Haskell είναι μαθηματικές συναρτήσεις ενδιάμεσα. Υπάρχει μόνο ένα μικρό πρόβλημα: η μαθηματική συνάρτηση δεν εκτελεί κανέναν κώδικα - ξέρει μόνο την απάντηση. Μια συνάρτηση στο Haskell πρέπει να υπολογίσει την απάντηση. Αυτό δεν είναι πρόβλημα εάν η απάντηση μπορεί να ληφθεί σε έναν πεπερασμένο αριθμό βημάτων, όσο μεγάλο κι αν είναι. Αλλά υπάρχουν ορισμένοι υπολογισμοί που περιλαμβάνουν αναδρομή και αυτοί μπορεί να μην ολοκληρωθούν ποτέ. Δεν μπορούμε απλώς να απαγορεύσουμε τις μη τερματιστικές συναρτήσεις στο Haskell, επειδή η διάκριση εάν μια συνάρτηση τερματίζεται ή όχι - το περίφημο πρόβλημα διακοπής - είναι άλυτο. Γι' αυτό οι επιστήμονες υπολογιστών σκέφτηκαν μια λαμπρή ιδέα, ή dirty hack ανάλογα με την άποψή σας, να επεκτείνουν κάθε τύπο με μια ειδική τιμή που ονομάζεται bottom (σημείωση του μεταφραστή: αυτός ο όρος (κάτω) ακούγεται κάπως ηλίθιος στα ρωσικά, αν κάποιος γνωρίζει μια καλή επιλογή, παρακαλώ να προτείνει.), το οποίο συμβολίζεται με _|_ ή σε Unicode ⊥. Αυτή η "τιμή" αντιστοιχεί σε έναν ελλιπή υπολογισμό. Άρα μια συνάρτηση που δηλώνεται ως:
f::Bool -> Bool
μπορεί να επιστρέψει True, False ή _|_; Το τελευταίο σημαίνει ότι η συνάρτηση δεν ολοκληρώνεται ποτέ.

Είναι ενδιαφέρον ότι μόλις αποδεχτείτε το κάτω μέρος στο σύστημα τύπων, είναι βολικό να αντιμετωπίζετε κάθε σφάλμα χρόνου εκτέλεσης ως κατώτατο και ακόμη και να επιτρέπετε σε μια συνάρτηση να επιστρέψει ρητά το κάτω μέρος. Το τελευταίο συνήθως γίνεται χρησιμοποιώντας την απροσδιόριστη έκφραση:
f::Bool -> Bool f x = απροσδιόριστο
Αυτός ο ορισμός περνά τον έλεγχο τύπου επειδή το undefined αξιολογεί στο κάτω μέρος, το οποίο περιλαμβάνεται σε όλους τους τύπους, συμπεριλαμβανομένου του Bool. Μπορείτε ακόμη να γράψετε:
f::Bool -> Bool f = απροσδιόριστο
(χωρίς x) γιατί το bottom είναι επίσης μέλος του τύπου Bool -> Bool.

Οι συναρτήσεις που μπορούν να επιστρέψουν κάτω ονομάζονται μερικές, σε αντίθεση με τις κανονικές συναρτήσεις που επιστρέφουν έγκυρα αποτελέσματα για όλα τα πιθανά ορίσματα.

Λόγω του πυθμένα, η κατηγορία των τύπων και συναρτήσεων Haskell ονομάζεται Hask, όχι Set. Από θεωρητικής σκοπιάς, αυτό είναι μια πηγή ατελείωτων επιπλοκών, οπότε σε αυτό το σημείο θα χρησιμοποιήσω το κρεοπωλείο μου και θα το ονομάσω μια μέρα. Από ρεαλιστική άποψη, μπορείτε να αγνοήσετε τις μη τερματικές συναρτήσεις και το κάτω μέρος και να αντιμετωπίσετε το Hask σαν να ήταν ένα σωστό σύνολο.

Γιατί χρειαζόμαστε ένα μαθηματικό μοντέλο;

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

Υπάρχουν επίσημα μέσα για την περιγραφή της σημασιολογίας μιας γλώσσας, αλλά λόγω της πολυπλοκότητάς τους, χρησιμοποιούνται κυρίως για απλοποιημένες, ακαδημαϊκές γλώσσες, παρά για τους πραγματικούς γίγαντες του βιομηχανικού προγραμματισμού. Ένα από αυτά τα εργαλεία ονομάζεται επιχειρησιακή σημασιολογία και περιγράφει τη μηχανική της εκτέλεσης του προγράμματος. Ορίζει έναν επισημοποιημένο, εξιδανικευμένο διερμηνέα. Η σημασιολογία βιομηχανικών γλωσσών όπως η C++ περιγράφεται τυπικά χρησιμοποιώντας άτυπη συλλογιστική, συχνά με όρους «αφηρημένης μηχανής».

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

Δεν έχει σημασία ότι οι προγραμματιστές δεν αποδεικνύουν ποτέ επίσημα την ορθότητα. Πάντα «νομίζουμε» ότι γράφουμε τα σωστά προγράμματα. Κανείς δεν κάθεται σε ένα πληκτρολόγιο και λέει: "Α, θα γράψω μόνο μερικές γραμμές κώδικα και θα δω τι θα συμβεί." (σημείωση μεταφραστή: ω, αν μόνο...)Πιστεύουμε ότι ο κώδικας που γράφουμε θα εκτελέσει ορισμένες ενέργειες που θα παράγουν τα επιθυμητά αποτελέσματα. Συνήθως εκπλήσσουμε πολύ αν δεν συμβαίνει αυτό. Αυτό σημαίνει ότι πραγματικά σκεφτόμαστε τα προγράμματα που γράφουμε, και συνήθως το κάνουμε τρέχοντας έναν διερμηνέα στο κεφάλι μας. Απλώς, είναι πολύ δύσκολο να παρακολουθείς όλες τις μεταβλητές. Οι υπολογιστές είναι καλοί στην εκτέλεση προγραμμάτων, οι άνθρωποι όχι! Αν ήμασταν, δεν θα χρειαζόμασταν υπολογιστές.

Υπάρχει όμως μια εναλλακτική. Ονομάζεται δηλωτική σημασιολογία και βασίζεται στα μαθηματικά. Στην δηλωτική σημασιολογία, περιγράφεται μια μαθηματική ερμηνεία για κάθε γλωσσική κατασκευή. Έτσι, εάν θέλετε να αποδείξετε μια ιδιότητα ενός προγράμματος, απλώς αποδεικνύετε ένα μαθηματικό θεώρημα. Νομίζετε ότι η απόδειξη θεωρημάτων είναι δύσκολη, αλλά στην πραγματικότητα, εμείς οι άνθρωποι κατασκευάζουμε μαθηματικές μεθόδους εδώ και χιλιάδες χρόνια, επομένως υπάρχει πολλή συσσωρευμένη γνώση που μπορεί να χρησιμοποιηθεί. Επίσης, σε σύγκριση με τα θεωρήματα που αποδεικνύουν οι επαγγελματίες μαθηματικοί, τα προβλήματα που συναντάμε στον προγραμματισμό τείνουν να είναι αρκετά απλά, αν όχι ασήμαντα. (σημείωση του μεταφραστή: για απόδειξη, ο συγγραφέας δεν προσπαθεί να προσβάλει τους προγραμματιστές.)

Εξετάστε τον ορισμό της παραγοντικής συνάρτησης στο Haskell, μια γλώσσα που προσφέρεται εύκολα στη δηλωτική σημασιολογία:
γεγονός n = προϊόν
Μια έκφραση είναι μια λίστα ακεραίων από το 1 έως το n. Η συνάρτηση προϊόντος πολλαπλασιάζει όλα τα στοιχεία μιας λίστας. Ακριβώς όπως ο ορισμός του factorial βγαλμένος από το σχολικό βιβλίο. Συγκρίνετε αυτό με το C:
int fact(int n) ( int i; int αποτέλεσμα = 1; for (i = 2; i<= n; ++i) result *= i; return result; }
Να συνεχίσω; (σημείωση του μεταφραστή: ο συγγραφέας εξαπάτησε λίγο παίρνοντας μια λειτουργία βιβλιοθήκης στο Haskell. Στην πραγματικότητα, δεν χρειαζόταν εξαπάτηση· μια ειλικρινής περιγραφή, εξ ορισμού, δεν είναι πιο δύσκολη):
γεγονός 0 = 1 γεγονός n = n * γεγονός (n - 1)
Εντάξει, θα παραδεχτώ αμέσως ότι ήταν φτηνό πλάνο! Το Factorial έχει έναν προφανή μαθηματικό ορισμό. Ο οξυδερκής αναγνώστης μπορεί να ρωτήσει: Ποιο είναι το μαθηματικό μοντέλο για την ανάγνωση ενός χαρακτήρα από το πληκτρολόγιο ή την αποστολή ενός πακέτου μέσω ενός δικτύου; Για μεγάλο χρονικό διάστημα, αυτή θα ήταν μια άβολη ερώτηση, που θα οδηγούσε σε μάλλον συγκεχυμένες εξηγήσεις. Η δηλωτική σημασιολογία φαινόταν να είναι ακατάλληλη για έναν σημαντικό αριθμό σημαντικών προβλημάτων που ήταν απαραίτητα για τη σύνταξη χρήσιμων προγραμμάτων και που θα μπορούσαν εύκολα να επιλυθούν από τη λειτουργική σημασιολογία. Η ανακάλυψη προήλθε από τη θεωρία της κατηγορίας. Ο Eugenio Moggi ανακάλυψε ότι τα υπολογιστικά εφέ μπορούν να μετατραπούν σε μονάδες. Αυτό αποδείχθηκε ότι ήταν μια σημαντική παρατήρηση που όχι μόνο έδωσε νέα ζωή στη δηλωτική σημασιολογία και έκανε τα καθαρά λειτουργικά προγράμματα πιο βολικά, αλλά παρείχε επίσης νέες πληροφορίες σχετικά με τον παραδοσιακό προγραμματισμό. Θα μιλήσω για τις μονάδες αργότερα όταν αναπτύξουμε πιο κατηγορηματικά εργαλεία.

Ένα από τα σημαντικά πλεονεκτήματα της ύπαρξης ενός μαθηματικού μοντέλου προγραμματισμού είναι η ικανότητα εκτέλεσης επίσημης απόδειξης της ορθότητας του λογισμικού. Αυτό μπορεί να μην φαίνεται τόσο σημαντικό όταν γράφετε λογισμικό για καταναλωτές, αλλά υπάρχουν τομείς προγραμματισμού όπου το κόστος της αποτυχίας μπορεί να είναι τεράστιο ή όπου η ανθρώπινη ζωή κινδυνεύει. Αλλά ακόμη και όταν γράφετε εφαρμογές Ιστού για το σύστημα υγειονομικής περίθαλψης, μπορείτε να εκτιμήσετε την ιδέα ότι οι λειτουργίες και οι αλγόριθμοι από την τυπική βιβλιοθήκη Haskell συνοδεύονται από αποδείξεις ορθότητας.

Λειτουργίες καθαρισμού και βρωμιάς

Αυτό που ονομάζουμε συναρτήσεις στη C++ ή σε οποιαδήποτε άλλη επιτακτική γλώσσα δεν είναι το ίδιο με αυτό που οι μαθηματικοί αποκαλούν συναρτήσεις. Μια μαθηματική συνάρτηση είναι απλώς μια αντιστοίχιση από τιμές σε τιμές.

Μπορούμε να εφαρμόσουμε μια μαθηματική συνάρτηση σε μια γλώσσα προγραμματισμού: μια τέτοια συνάρτηση, δεδομένης μιας τιμής εισόδου, θα υπολογίσει την τιμή εξόδου. Μια συνάρτηση στο τετράγωνο ενός αριθμού πιθανότατα θα πολλαπλασιάσει την τιμή εισόδου από μόνη της. Θα το κάνει αυτό κάθε φορά που καλείται, και είναι εγγυημένο ότι θα παράγει το ίδιο αποτέλεσμα κάθε φορά που καλείται με το ίδιο όρισμα. Το τετράγωνο του αριθμού δεν αλλάζει με τις φάσεις της σελήνης.

Επιπλέον, ο υπολογισμός του τετραγώνου ενός αριθμού δεν θα πρέπει να έχει την παρενέργεια να δώσει στον σκύλο σας μια νόστιμη απόλαυση. Η «συνάρτηση» που το κάνει αυτό δεν μπορεί εύκολα να μοντελοποιηθεί από μια μαθηματική συνάρτηση.

Στις γλώσσες προγραμματισμού, οι συναρτήσεις που παράγουν πάντα το ίδιο αποτέλεσμα στα ίδια ορίσματα και δεν έχουν παρενέργειες ονομάζονται καθαρές. Σε μια καθαρή λειτουργική γλώσσα όπως η Haskell, όλες οι συναρτήσεις είναι καθαρές. Αυτό καθιστά ευκολότερο τον προσδιορισμό της δηλωτικής σημασιολογίας αυτών των γλωσσών και τη μοντελοποίησή τους χρησιμοποιώντας τη θεωρία κατηγοριών. Για άλλες γλώσσες, μπορείτε πάντα να περιοριστείτε σε ένα καθαρό υποσύνολο ή να σκεφτείτε τις παρενέργειες ξεχωριστά. Αργότερα θα δούμε πώς τα monads μας επιτρέπουν να μοντελοποιούμε όλα τα είδη εφέ χρησιμοποιώντας μόνο καθαρές συναρτήσεις. Ως αποτέλεσμα, δεν χάνουμε τίποτα περιοριζόμενοι σε μαθηματικές συναρτήσεις.

Παραδείγματα τύπων

Μόλις αποφασίσετε ότι οι τύποι είναι σύνολα, μπορείτε να βρείτε μερικά αρκετά εξωτικά παραδείγματα. Για παράδειγμα, ποιος τύπος αντιστοιχεί στο κενό σύνολο; Όχι, δεν είναι void στη C++, αν και αυτός ο τύπος ονομάζεται Void στο Haskell. Αυτός είναι ένας τύπος που δεν συμπληρώνεται με καμία τιμή. Μπορείτε να ορίσετε μια συνάρτηση που παίρνει ένα Void, αλλά δεν μπορείτε ποτέ να την καλέσετε. Για να το καλέσετε, πρέπει να δώσετε μια τιμή τύπου Void, και απλά δεν υπάρχει. Όσο για το τι μπορεί να επιστρέψει αυτή η λειτουργία, δεν υπάρχουν περιορισμοί. Μπορεί να επιστρέψει οποιοδήποτε τύπο (αν και αυτό δεν θα συμβεί ποτέ γιατί δεν μπορεί να κληθεί). Με άλλα λόγια, είναι μια συνάρτηση που είναι πολυμορφική στον τύπο επιστροφής. Οι Χασκλέρ το ονόμασαν:
παράλογο::Κενό -> α
(Σημείωση του μεταφραστή: είναι αδύνατο να οριστεί μια τέτοια συνάρτηση στη C++: στη C++, κάθε τύπος έχει τουλάχιστον μία τιμή.)

(Θυμηθείτε ότι η a είναι μια μεταβλητή τύπου, η οποία μπορεί να είναι οποιοσδήποτε τύπος.) Αυτό το όνομα δεν είναι τυχαίο. Υπάρχει μια βαθύτερη ερμηνεία των τύπων και των συναρτήσεων από άποψη λογικής που ονομάζεται ισομορφισμός Curry-Howard. Ο τύπος Void αντιπροσωπεύει την αναλήθεια και η παράλογη συνάρτηση αντιπροσωπεύει τον ισχυρισμό ότι κάτι προκύπτει από μια αναλήθεια, όπως στη λατινική φράση "ex falso sequitur quodlibet". (σημείωση του μεταφραστή: οτιδήποτε προκύπτει από το ψεύδος.)

Ακολουθεί ο τύπος που αντιστοιχεί στο σετ μονότονων. Αυτός είναι ένας τύπος που έχει μόνο μία πιθανή τιμή. Αυτή η έννοια είναι απλώς «υπάρχει». Μπορεί να μην το αναγνωρίσετε αμέσως, αλλά είναι άκυρο στη C++. Σκεφτείτε τις λειτουργίες από και προς αυτόν τον τύπο. Μια κενή συνάρτηση μπορεί πάντα να κληθεί. Εάν είναι καθαρή συνάρτηση, θα επιστρέφει πάντα το ίδιο αποτέλεσμα. Ακολουθεί ένα παράδειγμα μιας τέτοιας συνάρτησης:
int f44() (επιστροφή 44; )
Μπορεί να πιστεύετε ότι αυτή η συνάρτηση δέχεται "τίποτα", αλλά όπως μόλις είδαμε, μια συνάρτηση που δέχεται "τίποτα" δεν μπορεί να κληθεί επειδή δεν υπάρχει τιμή που να αντιπροσωπεύει τον τύπο "τίποτα". Τι δέχεται λοιπόν αυτή η συνάρτηση; Εννοιολογικά, χρειάζεται μια εικονική τιμή που έχει μόνο μία παρουσία, επομένως δεν χρειάζεται να την προσδιορίσουμε ρητά στον κώδικα. Ο Haskell, ωστόσο, έχει ένα σύμβολο για αυτό το νόημα: το κενό ζευγάρι παρενθέσεων (). Έτσι, λόγω μιας αστείας σύμπτωσης (ή όχι μιας σύμπτωσης;), η κλήση μιας συνάρτησης από το void φαίνεται ίδια και στη C++ και στη Haskell. Επιπλέον, λόγω της αγάπης του Haskell για τη συντομία, το ίδιο σύμβολο () χρησιμοποιείται για τον τύπο, τον κατασκευαστή και την μοναδική τιμή που αντιστοιχεί σε ένα σύνολο singleton. Εδώ είναι η συνάρτηση στο Haskell:
f44::() -> Ακέραιος f44() = 44
Η πρώτη γραμμή δηλώνει ότι το f44 θα μετατρέψει τον τύπο () που ονομάζεται "unit" στον τύπο Integer. Η δεύτερη γραμμή καθορίζει ότι το f44 χρησιμοποιεί αντιστοίχιση μοτίβων για να μετατρέψει τον μοναδικό κατασκευαστή για ένα, δηλαδή (), στον αριθμό 44. Καλείτε αυτήν τη συνάρτηση παρέχοντας την τιμή ():
f44()
Σημειώστε ότι κάθε συνάρτηση ενός ισοδυναμεί με την επιλογή ενός στοιχείου από τον τύπο προορισμού (εδώ, επιλέγεται ο ακέραιος αριθμός 44). Στην πραγματικότητα, μπορείτε να σκεφτείτε το f44 ως μια άλλη αναπαράσταση του αριθμού 44. Αυτό είναι ένα παράδειγμα για το πώς μπορούμε να αντικαταστήσουμε την άμεση αναφορά στα στοιχεία ενός συνόλου με μια συνάρτηση (βέλος). Οι συναρτήσεις από ένα σε συγκεκριμένο τύπο Α αντιστοιχούν ένα προς ένα με τα στοιχεία του συνόλου Α.

Τι γίνεται με τις συναρτήσεις που επιστρέφουν void ή, στο Haskell, επιστρέφουν ένα; Στην C++ τέτοιες συναρτήσεις χρησιμοποιούνται για παρενέργειες, αλλά γνωρίζουμε ότι τέτοιες συναρτήσεις δεν είναι πραγματικές συναρτήσεις με τη μαθηματική έννοια της λέξης. Μια καθαρή συνάρτηση που επιστρέφει ένα δεν κάνει τίποτα: απορρίπτει το όρισμά της.

Μαθηματικά, μια συνάρτηση από ένα σύνολο Α σε ένα σύνολο μονού αντιστοιχίζει κάθε στοιχείο σε ένα μεμονωμένο στοιχείο αυτού του συνόλου. Για κάθε Α υπάρχει ακριβώς μια τέτοια συνάρτηση. Εδώ είναι για τον Ακέραιο:
fInt::Integer -> () fInt x = ()
Του δίνετε οποιονδήποτε ακέραιο και επιστρέφει έναν. Στο πνεύμα της συντομίας, ο Haskell επιτρέπει τη χρήση μιας υπογράμμισης ως επιχείρημα, η οποία απορρίπτεται. Με αυτόν τον τρόπο, δεν χρειάζεται να βρείτε ένα όνομα για αυτό. Ο παραπάνω κώδικας μπορεί να ξαναγραφτεί ως εξής:
fInt::Integer -> () fInt_ = ()
Σημειώστε ότι η εκτέλεση αυτής της συνάρτησης δεν είναι μόνο ανεξάρτητη από την τιμή που της μεταβιβάστηκε, αλλά και ανεξάρτητη από τον τύπο του ορίσματος.

Οι συναρτήσεις που μπορούν να οριστούν με τον ίδιο τύπο για οποιονδήποτε τύπο ονομάζονται παραμετρικά πολυμορφικές. Μπορείτε να εφαρμόσετε μια ολόκληρη οικογένεια τέτοιων συναρτήσεων με μία μόνο εξίσωση, χρησιμοποιώντας μια παράμετρο αντί για συγκεκριμένο τύπο. Πώς να καλέσετε μια πολυμορφική συνάρτηση από οποιονδήποτε τύπο σε ένα; Φυσικά, θα το ονομάσουμε μονάδα:
μονάδα::a -> () μονάδα _ = ()
Στην C++ θα το εφαρμόσατε ως εξής:
πρότυπο κενή μονάδα (T) ()
(σημείωση του μεταφραστή: για να βοηθήσετε τον μεταγλωττιστή να το βελτιστοποιήσει στο noop, είναι καλύτερα ως εξής):
πρότυπο κενή μονάδα (T&&) ()
Στη συνέχεια στην «τυπολογία των τύπων» υπάρχει ένα σύνολο δύο στοιχείων. Στη C++ λέγεται bool, και στο Haskell, δεν αποτελεί έκπληξη, Bool. Η διαφορά είναι ότι στη C++ το bool είναι ένας ενσωματωμένος τύπος, ενώ στο Haskell μπορεί να οριστεί ως εξής:
data Bool = True | Ψευδής
(Αυτός ο ορισμός πρέπει να διαβαστεί ως εξής: Το Bool μπορεί να είναι είτε True είτε False.) Κατ' αρχήν, θα ήταν δυνατό να περιγραφεί αυτός ο τύπος στη C++:
enum bool(true, false);
Αλλά ένας αριθμός C++ είναι στην πραγματικότητα ένας ακέραιος αριθμός. Θα μπορούσε κανείς να χρησιμοποιήσει ένα C++11 "class enum", αλλά στη συνέχεια θα έπρεπε να χαρακτηρίσει την τιμή με το όνομα της κλάσης: bool::true ή bool::false, για να μην αναφέρουμε την ανάγκη να συμπεριλάβουμε την αντίστοιχη κεφαλίδα σε κάθε αρχείο που το χρησιμοποιεί.

Οι συναρτήσεις Pure Bool επιλέγουν απλώς δύο τιμές από τον τύπο προορισμού, μία που αντιστοιχεί σε True και μία αντιστοιχεί σε False.

Οι συναρτήσεις στο Bool ονομάζονται κατηγορήματα. Για παράδειγμα, η βιβλιοθήκη Data.Char στο Haskell περιέχει πολλά κατηγορήματα, όπως IsAlpha ή isDigit. Υπάρχει παρόμοια βιβλιοθήκη στη C++ , το οποίο δηλώνει, μεταξύ άλλων, τις συναρτήσεις isalpha και isdigit, αλλά επιστρέφουν μια τιμή int και όχι boolean. Οι παρούσες κατηγόριες ορίζονται στο και ονομάζονται ctype::is(alpha, c) και ctype::is(ψηφίο, c).



 


Ανάγνωση:



Πώς να ρυθμίσετε σωστά τους χρονισμούς RAM;

Πώς να ρυθμίσετε σωστά τους χρονισμούς RAM;

Η RAM λειτουργεί με βάση τα σήματα ελέγχου από τον ελεγκτή μνήμης, ο οποίος βρίσκεται στη βόρεια γέφυρα του chipset (Intel) ή απευθείας...

Εγκατάσταση Navitel σε πλοηγό και υπολογιστή

Εγκατάσταση Navitel σε πλοηγό και υπολογιστή

Εάν πρέπει να εγκαταστήσετε χάρτες στο Garmin navigator, τότε έχετε έρθει στο σωστό μέρος. Παρακάτω θα δούμε διάφορους τρόπους για να το κάνετε αυτό. Ετσι...

Αλλάξτε τον κωδικό πρόσβασης στον διακομιστή Minecraft μέσω του προσωπικού σας λογαριασμού και στον πελάτη

Αλλάξτε τον κωδικό πρόσβασης στον διακομιστή Minecraft μέσω του προσωπικού σας λογαριασμού και στον πελάτη

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

Τι είναι το καλώδιο ηχείων

Τι είναι το καλώδιο ηχείων

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

τροφοδοσία-εικόνα RSS