Πέμπτη, 17 Δεκεμβρίου 2015

Όνομα Χώρου Τμήματος (NameSpace)-Οκνηρή αποτίμηση

Προχωρημένο θέμα!

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

Στο τμήμα ΚΛ η μεταβλητή Α θα έχει το εκτελέσιμο όνομα του ΚΛ ως πρόθεμα, μια τελεία και το όνομα Α. Έστω ότι το πρόγραμμα το βάζουμε σε ένα τμήμα Α. Τότε λόγω την Κάλεσε το τμήμα ΚΛ θα λέγεται Α[1]  αν το ΚΛ καλούσε μια φορά τον εαυτό του (κανονικά χωρίς την Κάλεσε δεν επιτρέπεται), τότε τη δεύτερη φορά θα είχε όνομα Α[2] και η Α το Α[2].Α έτσι θα συνυπήρχαν οι δυο Α με διαφορετικό πρόθεμα. Αν θέλουμε να φτιάξουμε τοπική Α ενώ υπάρχει Α τότε θα φτιαχτεί ακριβώς μια ίδια, αλλά θα μπει πρώτη στη σειρά αναζήτησης. Έτσι γίνεται να συνυπάρχουν δυο Α[2].Α με διαφορετικές τιμές αλλά μια μπορεί να διαβαστεί, η πιο πρόσφατη. Στο παράδειγμα χρησιμοποιούμε τη Μ ως τοπική ενώ υπάρχει μια στο ΚΛ. Στο τέλος μένει μόνο η αρχική Μ και το βλέπουμε στη εκτύπωση. Το Α[1], το όνομα του εκτελέσιμου τμήματος, ή συναρτήσεως, είναι το όνομα χώρου, όπου θα πάρουν πρόθεμα οι μεταβλητές, οι πίνακες, τα τμήματα, οι κλάσεις, οι συναρτήσεις.οι ομάδες. Στις ομάδες το όνομα χώρου μεγαλώνει για τα δικά του μέλη με το όνομα της ομάδας. Στις ανώνυμες ομάδες δεν υπάρχει όνομα χώρου, ούτε καν όνομα ομάδας, αλλά αποδίδονται πρόσκαιρα αν χρειαστεί, το όνομα χώρου από το τρέχον όνομα και το όνομα ομάδας ένα τυχαίο όνομα, που έχει μια ιδιαιτερότητα και δεν εμφανίζεται!

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

Ο τρόπος που περνάμε τις τιμές λέγεται Οκνηρή αποτίμηση. Διότι ουσιαστικά περνάμε αυτό που θα αποτιμηθεί αργότερα, και όχι την ώρα που το περνάμε. Θα μπορούσε να πει κανείς ότι το ίδιο συμβαίνει αν περάσουμε μια αναφορά σε συνάρτηση. Αλλά δεν είναι έτσι, με το πέρασμα της αναφοράς σε συνάρτηση περνάμε λογική όχι και δεδομένα, και δεν έχουμε το "παράθυρο" στο αρχικό τμήμα για οποιονδήποτε χειρισμό. Δεν έχουμε δηλαδή πέρασμα συνάρτησης αλλά μέρους του τμήματος που εκτελείται αργότερα μέσα σε άλλο τμήμα, ή σε μεγαλύτερο βάθος. Είναι σαν ένα πέρασμα με αναφορά αλλά εδώ η αναφορά έχει πολλά με βασικότερο το τμήμα!
Η ιδέα της Οκνηρής αποτίμησης φαίνεται και στο παράδειγμα του συναρτησιακού προγραμματισμού εδώ

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

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

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




Τμήμα ΚΛ {
      Συνάρτηση Λ {
      διαβασε
      β++
      =β
      }
      Συνάρτηση Μετά$ {
            φέρε 2 ' μετακινεί το δεύτερο στοιχείο ως πρώτο
            Διαβασε έκφραση$
            β$=" Τμήμα  Α { Τμήμα " + γράμμα$+ {
            }
            Αν όχι κενό Τότε {
                  Αν έκφραση$<>"" τότε {
                        β$=β$+"Διάβασε Τοπικά "+έκφραση$+{
                        }
                  }
                  Διαβασε έκφραση$
            }
            Αν όχι κενό Τότε {
                  β$=β$+έκφραση$+{
                  }
                  Διαβασε έκφραση$
            }            
            = "{"+β$+"Σειρά "+έκφραση$+" }  : Α : = Αριθμός }"
      }
      Τμήμα β {
            \\διαβάζουμε δυο συναρτήσεις
            διάβασε &α(), &β()
            \\ η πρώτη συνάρτηση αλλάζει την Κ στο ΚΛ τμήμα
            \\ η δεύτερη συνάρτηση μας δείχνει το Κ από το ΚΛ
            \\ Κάθε φορά που χρησιμοποιούμε την α() παίρνουμε ένα νέο αποτέλεσμα
            Τύπωσε α(1) , β()
            Τμήμα Γ {
                 διάβασε &α(), &β()
                 Τύπωσε α(-1), β()
            }
            Γ &α(), &β()
      }
      Α=10
      Κ=30
      Χ=3
      M=500
      Λογική$= {
            Τοπική Μ
            Αν Κ<41 τότε { Μ=-Κ } αλλιώς Μ=Κ
            Χ++
      }
     Για ι=1 έως 10 {
           Κάλεσε β Μετά$(τμήμα$,"Μ","Α*Λ(&Κ)*Μ") ,Μετά$(τμήμα$, "",λογική$, "Μ+100*Χ")
      }
      Τύπωσε Α, Κ, Χ, M
}
Κάλεσε ΚΛ


Ας δούμε αυτή την έκφραση  Μετά$(τμήμα$,"Μ","Α*Λ(&Κ)*Μ" δίνουμε το τμήμα, ως όνομα χώρου, μετά ζητάμε να διαβάσει τη Μ (τοπική), και να εκτελέσει μια έκφραση με τα Α, Κ, Μ και Λ() του τμήματος. Το Κ το περνάμε με αναφορά στο Λ. Η τιμή της έκφρασης επιστρέφεται κάθε φορά που χρησιμοποιούμε την συνάρτηση.
Στην έκφραση Μετά$(τμήμα$"",λογική$"Μ+100*Χ")  δίνουμε το τμήμα, ως όνομα χώρου, μετά αφήνουμε κενή το πεδίο για την διάβασε, μετά βάζουμε ένα ακόμη με μερικές εντολές, όπως να φτιάξει την τοπική Μ να κοιτάξει το Κ και ανάλογα να φτιάξει την Μ και να αυξήσει το Χ. Τέλος δίνουμε την έκφραση που θα επιστρέψει τιμή.  
Καλούμε το Γ και περνάμε ξανά τον ορισμό σε άλλες συναρτήσεις, όπου εδώ μάλιστα αλλάζουμε και την είσοδο στην πρώτη (Στο Μ)
Και οι δυο συναρτήσεις φτιάχνουν από μια Μ, η μια με Διάβασε τοπικά και η άλλη με Τοπική.
Στο τέλος τυπώνουμε τα Α,Κ,Χ και Μ. 
10 50 23 500
Η Α δεν άλλαξε
Η Κ από 30 πήγε στο 50
Το Χ από 3 πήγε στο 23
Η Μ έμεινε ως είχε - επειδή είχαμε τοπικές στις συναρτήσεις.

Εδώ ας θυμηθούμε ότι τα τμήματα σε μια γραμμή εκτέλεσης μοιράζονται έναν σωρό τιμών ενώ οι συναρτήσεις κάθε φορά που τρέχουν έχουν νέο σωρό, ακόμα και αν τρέχουν με αναδρομή. Στις συναρτήσεις οι μεταβλητές/εκφράσεις/αναφορές που δίνουμε μπαίνουν σε έναν νέο σωρό. Ότι έχει ο σωρός στο πέρας της χρήσης της συνάρτησης θα σβήσει. Δεν ισχύει αυτό στα τμήματα. Στην Μετ έχουμε φτιάξει μια συνάρτηση ανώνυμη, δηλαδή της μορφής "{=100}" (αυτή γυρίζει 100) αλλά η έκφραση διαφέρει. Επίσης έχουμε περισσότερες γραμμές αν χρειάζεται για να βάλουμε μερικά βοηθητικά, όπως μια διάβασε και μια ακόμα ένθεση κώδικα πριν τη τελική επιστροφή μέσω μιας έκφρασης.  Καλούμε την Α που αλλάζει όνομα και αυτή γυρίζει μια τιμή στο σωρό. Την διαβάζουμε με τον Αριθμό και την επιστρέφουμε.

Παρακάτω έχουμε το ίδιο πρόγραμμα αλλά έχουμε κάνει μια κλάση με το όνομα Μετά(), με αυτήν φτιάχνουμε δυο ομάδες και τις περνάμε στο β από εκεί παίρνουμε τις συναρτήσεις Αλφα() των αντικειμένων και τις χρησιμοποιούμε, και μετά τις περνάμε με αναφορά στο Γ. Και στις δυο περιπτώσεις η Αλφα() έχει μια Α την οποία έκανε ΚΛ.
Εδώ βλέπουμε μια ακόμα εντολή την Ανάθεσε που λειτουργεί μόνο σε ομάδες και βάζει δεύτερη αναφορά σε υπάρχουσα μεταβλητή (και σε συνάρτηση βάζει άλλο ορισμό, αφού ο ορισμός είναι η αναφορά της στη Μ2000). Αρχικά η κλάση έχει 

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

Τμήμα ΚΛ {
      Συνάρτηση Λ {
      διαβασε
      β++
      =β
      }
      Κλάση Μετά {
      Συνάρτηση ΑΛΦΑ {
      }
            Τμήμα Μετά {
                  φέρε 2 ' μετακινεί το δεύτερο στοιχείο ως πρώτο
                  Διαβασε έκφραση$
                  β$=" Τμήμα  Α { Τμήμα " + γράμμα$+ {
                  }
                  Αν όχι κενό Τότε {
                        Αν έκφραση$<>"" τότε {
                              β$=β$+"Διάβασε Τοπικά "+έκφραση$+{
                              }
                        }
                        Διαβασε έκφραση$
                  }
                  Αν όχι κενό Τότε {
                        β$=β$+έκφραση$+{
                        }
                        Διαβασε έκφραση$
                  }            
                  Βάλε  "{"+β$+"Σειρά "+έκφραση$+" }  : Α : = Αριθμός }"
                  Ανέθεσε .Αλφα()
            }
      }
      Τμήμα β {
            \\διαβάζουμε δυο συναρτήσεις
            Διάβασε Α, Β
            Ένωσε Α.Αλφα(), Β.Αλφα() στο α(), β()
            \\ η πρώτη συνάρτηση αλλάζει την Κ στο ΚΛ τμήμα
            \\ η δεύτερη συνάρτηση μας δείχνει το Κ από το ΚΛ
            \\ Κάθε φορά που χρησιμοποιούμε την α() παίρνουμε ένα νέο αποτέλεσμα
            Τύπωσε α(1) , β()
            Τμήμα Γ {
                 διάβασε &α(), &β()
                 Τύπωσε α(-1), β()
            }
            Γ &α(), &β()
      }
      Α=10
      Κ=30
      Χ=3
      M=500
      Λιστα
      Λογική$= {
            Τοπική Μ
            Αν Κ<41 τότε { Μ=-Κ } αλλιώς Μ=Κ
            Χ++
      }
     Για ι=1 έως 10 {
           Κάλεσε β Μετά(τμήμα$,"Μ","Α*Λ(&Κ)*Μ") ,Μετά(τμήμα$, "",λογική$, "Μ+100*Χ")
      }
      Τύπωσε Α, Κ, Χ, M
}
Κάλεσε ΚΛ

Αν θέλουμε να περνάμε και στο Γ τα αντικείμενα μπορούμε να το κάνουμε, θα τα περάσουμε με αναφορά:
      Τμήμα β {
            \\διαβάζουμε δυο συναρτήσεις
            Διάβασε Α, Β
            Ένωσε Α.Αλφα(), Β.Αλφα() στο α(), β()
            \\ η πρώτη συνάρτηση αλλάζει την Κ στο ΚΛ τμήμα
            \\ η δεύτερη συνάρτηση μας δείχνει το Κ από το ΚΛ
            \\ Κάθε φορά που χρησιμοποιούμε την α() παίρνουμε ένα νέο αποτέλεσμα
            Τύπωσε α(1) , β()
            Τμήμα Γ {
                 διάβασε,
                 Ένωσε Α.Αλφα(), Β.Αλφα() στο α(), β()
                 Τύπωσε α(-1), β()
            }
            Γ &Α,
      }