Διαδρομές
/
Julia
Julia
/
Ασκήσεις
/
Γκουρού βαθμολόγησης
Γκουρού βαθμολόγησης

Γκουρού βαθμολόγησης

Άσκηση εκμάθησης

Εισαγωγή

Μέχρι τώρα, το syllabus δεν έχει πει πολλά για τους τύπους, αλλά είναι σαφές ότι υπάρχουν στη Julia:

julia> vals = (42, 4.3, π, "hello", 'Q')
(42, 4.3, π, "hello", 'Q')
julia> typeof(vals)
Tuple{Int64, Float64, Irrational{:π}, String, Char}

Δεν προσδιορίσαμε ποτέ τους τύπους, αλλά η Julia τους ανέθεσε ούτως ή άλλως.

  1. Η Julia έχει types, οι οποίοι είναι κεντρικοί στον σχεδιασμό της.
  2. Η Julia συνήθως μπορεί να "μαντέψει" τον τύπο, χρησιμοποιώντας Type Inference.

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

Ανάθεση τύπου

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

Στους περισσότερους σύγχρονους επεξεργαστές, ένας ακέραιος έχει από προεπιλογή τον τύπο Int64. Είδαμε στην Έννοια Numbers ότι μια τιμή μπορεί να μετατραπεί σε έναν συγκεκριμένο μη προεπιλεγμένο τύπο.

julia> x = Int16(42)
42
julia> typeof(x)
Int16

Ωστόσο, η μεταβλητή x μπορεί ακόμα να εκχωρηθεί ξανά σε διαφορετικό τύπο:

julia> x = "changed"
"changed"
julia> typeof(x)
String

Αυτό είναι type instability, το οποίο είναι:

  • Πολύ βολικό σε μικρά σενάρια.
  • Κακό για την απόδοση και την αξιοπιστία σε μεγαλύτερα προγράμματα.

Αντ' αυτού, μπορούμε να ορίσουμε τον τύπο του x χρησιμοποιώντας τον τελεστή :::

julia> y::Int16 = 42
42
julia> typeof(y)
Int16
julia> y = "changed"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int16
The function `convert` exists, but no method is defined for this combination of argument types.

Τώρα το y είναι, και θα είναι πάντα, τύπου Int16. Έτσι, ο μεταγλωττιστής ξέρει πόσα byte να δεσμεύσει για αυτό, και μπορεί να βελτιστοποιήσει τον υπόλοιπο κώδικα ώστε να βασίζεται σε έναν σταθερό τύπο. Ως προς αυτό, η μεταβλητή είναι λίγο-πολύ παρόμοια με εκείνες σε μια στατικά τυποποιημένη γλώσσα όπως η C.

Η ιεραρχία των τύπων

Int64, Int16, String, Char: από πού "προέρχονται" αυτοί οι τύποι;

Σε πολλές αντικειμενοστρεφείς (OO) γλώσσες, κάθε τύπος είναι μια κλάση, η δημιουργία υποκλάσεων τα τακτοποιεί σε μια ιεραρχία κλάσεων, και οι μέθοδοι κλάσης ορίζουν τις συμπεριφορές.

Η Java και η Ruby είναι προφανή παραδείγματα αυτού του μοτίβου, αλλά ακόμα και η Python είναι παρόμοια εσωτερικά.

Η Julia δεν έχει κλάσεις.

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

Κι όμως, κοίτα αυτόν τον κώδικα:

julia> y::Int16 = 42
42
julia> typeof(y)
Int16
julia> supertype(Int16)
Signed
julia> supertypes(Int16)
(Int16, Signed, Integer, Real, Number, Any)

Συμπληρώνοντας κάποιες λεπτομέρειες:

  • Το Int16 είναι ένας τύπος, και μπορούμε να δημιουργήσουμε μεταβλητές αυτού του τύπου.
  • Το Int16 είναι υπότυπος του Signed, και η συνάρτηση supertype() μας το δείχνει.
  • Υπάρχει μια ιεραρχία τύπων, που ανεβαίνει μέσω των Integer, Real και Number μέχρι το Any στην κορυφή, και η subtypes() θα μας απαριθμήσει αυτόν τον κλάδο της ιεραρχίας.

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

julia> supertypes(String)
(String, AbstractString, Any)
julia> supertype(Any)
Any

Έτσι, η Julia δεν έχει ιεραρχία class, αλλά έχει ιεραρχία type.

Κάποια στιγμή θα προσπαθήσουμε να ξεμπερδέψουμε πώς λειτουργεί αυτό, αλλά υπάρχουν πολλά ακόμα να εξερευνήσουμε πρώτα.

Έλεγχος τύπων

Μπορούμε να χρησιμοποιήσουμε τη typeof() για να ελέγξουμε την ισότητα με τον συνηθισμένο τρόπο.

julia> typeof(11)
Int64
julia> typeof(11) == Int64
true
julia> typeof(11) == Number
false

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

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

julia> 12 isa Int64
true
julia> 12 isa Number
true
julia> isa(12, Number)
true
julia> 12 isa String
false

Σημείωσε ότι η isa περιμένει ένα value στα αριστερά, όχι ένα type.

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

julia> Int64 isa Number  ## Don't do this!
false
julia> Int64 <: Number
true

Αφηρημένοι έναντι συγκεκριμένων τύπων

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

Κάθε στοιχείο του δέντρου είναι ένα node, και αυτά μπορούν να χωριστούν σε κατηγορίες:

  1. Οι κόμβοι που έχουν υποτύπους ονομάζονται abstract.
  2. Οι κόμβοι-φύλλα, που δεν έχουν υποτύπους, ονομάζονται concrete.
julia> subtypes(Integer)  # an abstract type
3-element Vector{Any}:
 Bool
 Signed
 Unsigned
julia> subtypes(Int64)  # a concrete type
Type[]

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

julia> a::Int16 = 42
42
julia> typeof(a)
Int16
julia> b::Integer = 42
42
julia> typeof(b)
Int64

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

Οδηγίες

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

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

  • Μερικοί καθηγητές χρησιμοποιούν πραγματικούς αριθμούς (γιατί είναι ψείρες στην ακρίβεια), και θα χρειαστεί να τους μετατρέψεις στον τύπο δεδομένων UInt8.
  • Άλλοι καθηγητές χρησιμοποιούν ακέραιους με αρνητικούς αριθμούς (για να τιμωρήσουν ιδιαίτερα άτακτους μαθητές), και σε αυτές τις περιπτώσεις θα χρειαστεί να τους μετατρέψεις στον τύπο δεδομένων Int8.

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

  • Μερικοί καθηγητές χρησιμοποιούν Vectors ταξινομημένα σε αύξουσα σειρά για να αποθηκεύουν τους βαθμούς τους, γιατί είναι σχολαστικοί με τα δεδομένα τους.
  • Άλλοι καθηγητές χρησιμοποιούν Sets, τα οποία δεν είναι ταξινομημένα, για να αποθηκεύουν τους βαθμούς τους, γιατί είναι λίγο πιο τεμπέληδες.

Και στις δύο συναρτήσεις, θα χρειαστεί να χειριστείς μη έγκυρες εισόδους πετώντας ένα MethodError.

Note

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

throw(MethodError(f, args))

Όπου f είναι η συνάρτηση και args είναι μια πλειάδα με τα ορίσματα που δίνονται στη συνάρτηση. Με τη συνάρτηση demote(n), το f είναι demote και το args είναι (n,):

throw(MethodError(demote, (n,)))

1. Υποβάθμισε τους βαθμούς

Υλοποίησε τη μέθοδο demote(n).

  • Με είσοδο Float64, θα πρέπει να στρογγυλοποιεί προς τα πάνω στον πλησιέστερο ακέραιο και να επιστρέφει έναν τύπο δεδομένων UInt8.
  • Με έναν οποιονδήποτε Integer, θα πρέπει να επιστρέφει τον ίδιο ακέραιο σε τύπο δεδομένων Int8.
  • Όλες οι άλλες είσοδοι θα πρέπει να πετούν ένα MethodError.
julia> demote(4.2)::UInt8
5

julia> demote(4)::Int8
4

julia> demote("hi")
MethodError: no method matching demote(::String)     #output truncated

2. Προεπεξεργάσου τα δεδομένα

Υλοποίησε τη μέθοδο preprocess(coll).

  • Με είσοδο Vector, θα πρέπει να υποβιβάζει όλους τους αριθμούς και να αντιστρέφει το διάνυσμα.
  • Με είσοδο Set, θα πρέπει να υποβιβάζει όλους τους αριθμούς και να επιστρέφει ένα ταξινομημένο διάνυσμα σε φθίνουσα σειρά.
  • Όλες οι άλλες είσοδοι θα πρέπει να πετούν ένα MethodError.
julia> preprocess([1, 2, 3])
3-element Vector{Int8}:
 3
 2
 1

julia> preprocess(Set([2.2, 5.8, 3.4]))
3-element Vector{UInt8}:
 6
 4
 3

julia> preprocess(42)
MethodError: no method matching preprocess(::Int64)     #output truncated
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
Julia Exercism

Έτοιμος να ξεκινήσεις την άσκηση Γκουρού βαθμολόγησης;

Γράψου στο Exercism για να μάθεις και να κατακτήσεις Julia με 35 έννοιες128 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.