Εφαρμογές#

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

Κατά bit: λογική σε bit ακεραίων#

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

Τελ.

Διαβάζεται ως

Κανόνας ανά bit

&

AND κατά bit

κάθε bit εξόδου = a∧b

|

OR κατά bit

κάθε bit εξόδου = a∨b

^

XOR κατά bit

κάθε bit εξόδου = a⊕b

~

NOT κατά bit

κάθε bit εξόδου = ¬a

<<

αριστερή ολίσθηση

ολίσθηση bit προς τα αριστερά, γέμισμα με μηδενικά από τα δεξιά

>>

δεξιά ολίσθηση

ολίσθηση bit προς τα δεξιά

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

Θέση, καθάρισμα, εναλλαγή, έλεγχος μιας σημαίας#

Οι τέσσερις βασικές πράξεις σημαίας σε ένα μόνο bit:

use constant FLAG_VERBOSE  => 0x01;
use constant FLAG_DRY_RUN  => 0x02;
use constant FLAG_RECURSE  => 0x04;
use constant FLAG_FORCE    => 0x08;

my $flags = 0;

$flags |=  FLAG_VERBOSE;       # SET    -- OR with the bit
$flags |=  FLAG_DRY_RUN;       # SET another
$flags &= ~FLAG_DRY_RUN;       # CLEAR  -- AND with the inverted bit
$flags ^=  FLAG_VERBOSE;       # TOGGLE -- XOR with the bit
my $on = $flags & FLAG_RECURSE;# TEST   -- AND, then test truthiness

Καθεμία από αυτές είναι μια εφαρμογή ενός bit ενός λογικού τελεστή. Η θέση είναι bit flag, το καθάρισμα είναι bit ¬flag, η εναλλαγή είναι bit flag, ο έλεγχος είναι bit flag.

Ανταλλαγή με XOR: ανταλλαγή χωρίς προσωρινή τιμή#

Το XOR έχει δύο ιδιότητες που συνδυάζονται σε ένα αξιομνημόνευτο τέχνασμα: a a = 0, και a b b = a. Εφαρμόστε τις διαδοχικά και μπορείτε να ανταλλάξετε δύο ακεραίους χωρίς τρίτη μεταβλητή:

my ($a, $b) = (0xFEED, 0xBEEF);

$a ^= $b;     # a := a ⊕ b
$b ^= $a;     # b := b ⊕ (a ⊕ b) = a
$a ^= $b;     # a := (a ⊕ b) ⊕ a  = b

print "a=$a b=$b\n";   # a=48879 b=65261  (0xBEEF, 0xFEED)

Το τέχνασμα δεν είναι στην πραγματικότητα χρήσιμο στην Perl — το ($a, $b) = ($b, $a) είναι ταχύτερο, σαφέστερο, και λειτουργεί σε οποιοδήποτε βαθμωτό συμπεριλαμβανομένων συμβολοσειρών και αναφορών. Αλλά εμφανίζεται σε δύο σημεία που έχουν σημασία:

  • Ενσωματωμένος κώδικας χωρίς ελεύθερο καταχωρητή. Ένας μικροελεγκτής με τρεις τιμές να ζογκλάρει σε δύο καταχωρητές καταφεύγει σε αυτό.

  • Λαογραφία συνεντεύξεων. Το να γνωρίζετε ότι υπάρχει και γιατί λειτουργεί (το XOR είναι το ίδιο το αντίστροφό του) αξίζει τα τριάντα δευτερόλεπτα που απαιτούνται για να το διαβάσετε.

Ο λόγος που λειτουργεί είναι ακριβώς η λογική ταυτότητα από το κεφάλαιο του πίνακα αληθείας: x y y = x. Καθεμία από τις τρεις παραπάνω γραμμές είναι μία εφαρμογή αυτής της ταυτότητας.

Συνηθισμένα τεχνάσματα bit#

Μια χούφτα μοτίβων που θα δείτε σε κώδικα ευαίσθητο στην απόδοση:

$x &  ($x - 1)         # $x with its lowest set bit cleared
($x & ($x - 1)) == 0   # true when $x is a power of two (and non-zero)
$x | -$x               # signed: zero iff $x was zero, non-zero otherwise
($x >> 31) & 1         # the sign bit, on a 32-bit signed integer
1 << $n                # the integer with only bit $n set
$x & (1 << $n)         # is bit $n set in $x?

Καθένα από αυτά είναι μια άσκηση στην παρακολούθηση τού τι κάνουν τα bit — καθαρός λογικός συλλογισμός εφαρμοσμένος 32 (ή 64) φορές παράλληλα.

Κανονικές εκφράσεις: λογική σε σύνολα συμβολοσειρών#

Μια regex ταιριάζει σε ένα σύνολο συμβολοσειρών. Το κενό σύνολο, το μονοσύνολο {"foo"}, το άπειρο σύνολο «οτιδήποτε ξεκινά με ψηφίο» — όλα είναι σύνολα, και η regex δηλώνει ένα από αυτά.

Μόλις δείτε μια regex ως σύνολο, οι λογικές πράξεις έχουν γεωμετρικό νόημα:

Λογική πράξη

Σε σύνολα

Σε σύνταξη regex

OR (∨)

ένωση

εναλλαγή: foo|bar

AND (∧)

τομή

ζεύγος πρόσθιων διεκδικήσεων: (?=.{4})(?=\d+$)

NOT (¬)

συμπλήρωμα

αρνητική πρόσθια διεκδίκηση: (?!foo)

AND-NOT (a ∧ ¬b)

διαφορά

(?=A)(?!B)A

Δύο συγκεκριμένα σημεία που αξίζει να ξεχωρίσουμε.

Η εναλλαγή είναι OR πάνω σε σύνολα#

$s =~ /yes|no|maybe/;

Ταιριάζει στην ένωση τριών μονοσυνόλων. Δεν υπάρχει τίποτε περισσότερο σε αυτό· το | στη σύνταξη regex είναι ακριβώς το λογικό ∨.

Μέσα σε μια κλάση χαρακτήρων το νόημα είναι το ίδιο:

$s =~ /[abc]/;        # union of {"a"}, {"b"}, {"c"}
$s =~ /[^abc]/;       # complement: anything NOT in {"a","b","c"}

Το [^...] είναι η σύνταξη regex για το ¬ εφαρμοσμένο σε ένα σύνολο χαρακτήρων.

Οι διεκδικήσεις γύρω είναι AND και NOT#

Μια regex χωρίς διεκδικήσεις γύρω καταναλώνει χαρακτήρες καθώς ταιριάζει· τα δύο άκρα μιας εναλλαγής A|B δεν μπορούν να ταιριάξουν αμφότερα στο ίδιο εύρος (μόνο ένας κλάδος κερδίζει). Για να εκφράσετε και το A και το B στην ίδια θέση, χρειάζεστε διεκδίκηση γύρω: μια διεκδίκηση μηδενικού πλάτους που απαιτεί μια ιδιότητα χωρίς κατανάλωση.

# matches only if the rest of the string is BOTH digits AND ≤ 4 chars
$s =~ /^(?=\d+$)(?=.{1,4}$)/;
#       \_____/\_______/
#         A         B          intersection: A ∧ B

Το (?=...) είναι θετική πρόσθια διεκδίκηση· το (?!...) είναι αρνητική πρόσθια διεκδίκηση (το λογικό NOT). Συνδυάζοντάς τα σας δίνεται η πλήρης άλγεβρα συνόλων πάνω σε κατηγορήματα regex:

# "starts with a digit but is not the literal '0'":
# (digit) ∧ ¬(literal "0")
$s =~ /^(?=\d)(?!0$)/;

Γιατί βοηθά αυτό το πλαίσιο#

Μόλις διαβάσετε τη regex με αυτόν τον τρόπο, η αναγνωσιμότητα σύνθετων μοτίβων βελτιώνεται δραματικά. Μια regex με δύο πρόσθιες διεκδικήσεις δεν είναι «δύο regex κολλημένες μαζί» — είναι η τομή δύο συνόλων. Μια αρνητική πρόσθια διεκδίκηση ακολουθούμενη από μια θετική αντιστοιχία δεν είναι «πρώτα απόρριψη, μετά αντιστοιχία» — είναι διαφορά συνόλων. Η λογική άλγεβρα που ήδη γνωρίζετε είναι η άλγεβρα των regex· μόνο ο συμβολισμός αλλάζει.

Ροή ελέγχου: λογική βραχυκυκλώματος ως υπό συνθήκη εκτέλεση#

Το κεφάλαιο για τους τελεστές εισήγαγε τον κανόνα επιστροφής τελεστέου για τα &&, ||, και //. Αυτός ο κανόνας, συν η προτεραιότητα, παράγει μια μικρή οικογένεια ιδιωμάτων που αντικαθιστούν τη ρητή if/else για σύντομη λογική υπό συνθήκη:

# defaulting
my $port = $cfg{port} // 8080;

# guard with side-effect
open my $fh, '<', $path  or die "open $path: $!";

# lazy initialisation (set if currently false)
$cache{$key} ||= compute($key);

# lazy initialisation (set if currently undef — a real `0` is kept)
$cfg{retries} //= 3;

# guard chain: do step 2 only if step 1 succeeded
my $rc = step_one() && step_two();

# logical selection inside an expression
my $label = $count == 1 ? "1 item" : "$count items";

Καθένα από αυτά είναι μια λογική έκφραση επιλεγμένη για τις παρενέργειές της — το βραχυκύκλωμα αποφασίζει αν θα εκτελεστεί καν ο δεξής τελεστέος. Το open ... or die λειτουργεί ακριβώς επειδή το or δεν αποτιμά τη δεξιά πλευρά του όταν η αριστερή είναι αληθής.

Δύο συμβουλές.

Χρησιμοποιήστε // και //= όταν το 0 ή το "" είναι έγκυρη τιμή. Αυτή η μεμονωμένη αλλαγή έχει αποτρέψει περισσότερα σφάλματα από οποιοδήποτε άλλο σύγχρονο ιδίωμα της Perl· το || που πέφτει σε προεπιλογή πάνω σε ρυθμισμένο μηδέν είναι ένας από τους κλασικούς τρόπους απώλειας δεδομένων.

Καταφύγετε στο ?: όταν διαφορετικά θα δομούσατε μια τριάδα if/else/βαθμωτή-ανάθεση. Ο τριαδικός διατηρεί την έκφραση ως έκφραση και την ανάθεση σε μία γραμμή:

# verbose
my $kind;
if ($n == 1) { $kind = 'singular' }
else         { $kind = 'plural'   }

# idiomatic
my $kind = $n == 1 ? 'singular' : 'plural';

Μην εμφωλεύετε τον ?: πάνω από δύο επίπεδα βαθιά. Πέρα από τα δύο, η αλυσιδωτή μορφή είναι δυσκολότερη να διαβαστεί από την if/elsif/else. Ο τριαδικός είναι για επιλογή· οι διαδοχικές αποφάσεις ανήκουν σε ένα μπλοκ.

Τι πρέπει να θυμάστε από αυτό το κεφάλαιο#

  • Τα κατά bit &, |, ^, ~ είναι οι λογικοί τελεστές εφαρμοσμένοι ανά bit παράλληλα· οι θέση/καθάρισμα/εναλλαγή/έλεγχος σημαίας είναι οι τέσσερις εφαρμογές ενός bit.

  • Μια regex δηλώνει ένα σύνολο συμβολοσειρών· το | είναι ένωση, το [^...] είναι συμπλήρωμα, τα (?=) και (?!) φτιάχνουν τομή και διαφορά.

  • Τα &&, ||, //, ?: σας δίνουν το μεγαλύτερο μέρος της υπό συνθήκη ροής ελέγχου χωρίς να γράφετε if. Χρησιμοποιήστε // όταν το 0 είναι πραγματικό· χρησιμοποιήστε ?: για σύντομη επιλογή μέσα σε μια έκφραση.

Δείτε επίσης#

  • perlop — Κατά bit — ο σύντροφος αναφοράς για την ενότητα κατά bit, με την πλήρη σημασιολογία ολίσθησης και τις μορφές συμβολοσειράς bytes με κατάληξη &. |. ^. ~..

  • perlop — Σύνδεση — τα =~ και !~, οι τελεστές που συνδέουν συμβολοσειρές με αντιστοίχιση regex.

  • Οδηγός κανονικών εκφράσεων — η πλήρης αναφορά της γλώσσας regex.

  • perlop — Λογικοί — οι τελεστές βραχυκυκλώματος πίσω από τα ιδιώματα ροής ελέγχου.