Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Telecooperation/RBG Technische Universität Darmstadt Copyrighted material; for TUD student use only Grundlagen der Informatik 1 Thema 10: Zuweisungen und.

Ähnliche Präsentationen


Präsentation zum Thema: "Telecooperation/RBG Technische Universität Darmstadt Copyrighted material; for TUD student use only Grundlagen der Informatik 1 Thema 10: Zuweisungen und."—  Präsentation transkript:

1 Telecooperation/RBG Technische Universität Darmstadt Copyrighted material; for TUD student use only Grundlagen der Informatik 1 Thema 10: Zuweisungen und andere Effekte Prof. Dr. Max Mühlhäuser Dr. Guido Rößling

2 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zuweisungen und andere Effekte: Übersicht Funktionen mit Gedächtnis, Version 2 set! Beispiel: Implementierung eines Addressbuchs Wie Zuweisungen unserer Programmiermodell ändern Sequenzierung von Ausdrücken mit (begin..) Teilen, Äquivalenz und Identität Nutzen von Zustandsvariablen zur Kommunikation Zuweisungen und Modellierung, Performanz, Streams 2

3 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Wichtige Eigenschaften von Funktionen Egal, wie oft wir eine Funktion mit ein und derselben Eingabe benutzen, wir bekommen immer das gleiche Ergebnis An jeder Stelle eines Programms können wir einen Funktionsaufruf durch seine Definition oder seinen Wert ersetzen, ohne den Sinn des Programms zu verändern –Wir können (+ 3 5) durch 8 ersetzen –Wir können (map succ (list 3 5)) durch ((lambda (f a-list) … ) succ (list 3 5)) ersetzen, wobei … die Definition von map ist –Wir können (map succ (list 3 5)) durch (list 4 6) ersetzen 3

4 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Funktionen mit Gedächtnis Diese Eigenschaft wird manchmal Gleiches durch Gleiches ersetzen oder referentielle Transparenz genannt, dieser Programmierstil als rein funktional bezeichnet Die Eigenschaft folgt direkt aus der Definition des Substitutionsmodells Manchmal ist es jedoch praktischer, Funktionen mit Gedächtnis einsetzen zu können Beispiel: Implementieren eines Zählers –Wir wollen zum Beispiel zählen, wie oft die subst-Funktion während der Evaluation eines Programms in unserem Interpreter aufgerufen wird 4 Die Bedeutung einer Funktion wird vollkommen durch ihre Eingabe/Ausgabe - Relation charakterisiert

5 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Funktionen mit Gedächtnis Rein funktionaler Zähler: (define (count old-count) (+ old-count 1)) Problem: –Wie müssen die eval -Funktion modifizieren Sie muss die aktuelle Zählung als zusätzliche Eingabe annehmen, muss die neue Zählung als zusätzliche Ausgabe liefern –Wir müssen alle Funktionen modifizieren, die eval aufrufen eval-if, eval-app, run-program, … Sie alle müssen einen zusätzlichen Eingabe/Ausgabe - Parameter annehmen/liefern und die entsprechenden Zähler-Werte aller eval- Aufrufe zu ihrem eigenen Ausgabewert des Zählers hinzufügen –Diese Lösung ist in höchstem Maße unmodular! 5

6 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Funktionen mit Gedächtnis Was wir im Beispiel gerne hätten, ist eine Funktion mit Gedächtnis –Sie merkt sich den alten Wert des Zählers. –Wenn sie aufgerufen wird, löst sie einen Nebeneffekt (oder einfach einen Effekt) aus: sie erhöht den Wert des Zählers Dies ist ein Nebeneffekt, weil es nicht Teil der Eingabe/Ausgabe – Relation ist 6

7 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zuweisungen Ein set!-Ausdruck, auch bekannt als Zuweisung, hat folgende Form: –(set! var exp) Er besteht aus –Einer Variablen, der linken Seite –Einem Ausdruck, genannt rechte Seite. –Die linke Seite eines set!-Ausdrucks ist eine Konstante. –In dieser Veranstaltung verwenden wir nur Variablen, die entweder auf höchster Ebene oder in einem local-Ausdruck definiert sind. Der Wert eines set!-Ausdrucks ist undefiniert (wie bei einem define- Ausdruck) und irrelevant. Wichtig ist der Effekt beim Auswerten eines set!-Ausdrucks: Nach der Zuweisung werden alle Referenzen auf var zum Wert von exp evaluieren Wechseln Sie zur Sprache Advanced Student in DrScheme um set! benutzen zu können. 7

8 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zuweisungen Mit Zuweisungen könnte das Zähler-Beispiel wie folgt gelöst werden: Was bedeutet (define (increment-counter) … ) ? –Es bedeutet (define increment-counter (lambda () … ) –Es ist eine Funktion ohne Parameter! Wird aufgerufen mit (increment-counter) Verwechseln Sie nicht increment-counter und (increment- counter) –Eine Funktion ohne Parameter wäre (beinahe) nutzlos, wenn sie nur rein funktional / effektfrei ist: Sie wäre lediglich eine Konstante beinahe, weil diese Technik auch dafür benutzt werden kann, um Evaluation zu verhindern 8 ;; provide initial value for counter (define counter-value 0) ;; incrementing counter (define (increment-counter) (set! counter-value (succ counter-value))

9 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zuweisungen 9

10 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Funktionen mit Gedächtnis Ein anderes Beispiel: Führen eines Telefonbuchs Telefonbuch-Software leitest zumindest zwei Dienste: –Ein Dienst zum Nachschlagen der Telefonnummer einer Person –Ein Dienst zum Hinzufügen eines Namens und einer Telefonnummer zum Adressbuch Mögliche Oberfläche für die Software: 10

11 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Funktionen mit Gedächtnis Der zugehörige Code könnte folgendermaßen aussehen: 11 ;; lookup : symbol -> number or false ;; to lookup the number associated with name in ADDRESS-BOOK ;; if it doesn't find name, the function produces false (define (lookup name)...) ;; add-to-address-book : symbol number -> void ;; to add name and number to address-book (define (add-to-address-book name number)...) (define ADDRESS-BOOK (list (list 'Adam 1) (list 'Eve 2)))

12 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Funktionen mit Gedächtnis Stellen Sie sich nun folgende Interaktion mit DrScheme vor: Es ist unmöglich, dies mit effektfreien Funktionen zu erreichen! –In einem effektfreien Programm geben Funktionen immer das gleiche Ergebnis für die gleichen Parameter zurück Ohne Zuweisungen müsste add-to-address das alte Adressbuch verarbeiten und dann ein neues erzeugen, das bei zukünftigen Aufrufen von lookup weiter benutzt werden könnte. 12 > (lookup 'Adam) 1 > (lookup 'Dawn) false > (add-to-address-book 'Dawn 4) > (lookup 'Dawn) 4

13 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Funktionen mit Gedächtnis Lösung mit Zuweisungen Die Verwendung von ! in allen Funktionen, die Zuweisungen gebrauchen, ist eine sinnvolle Konvention, wird aber nicht vom Interpreter erzwungen Wir nennen ADDRESS-BOOK eine Zustandsvariable 13 (define (add-to-address-book! name number) (set! ADDRESS-BOOK (cons (list name number) ADDRESS-BOOK)))

14 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Wie sich unser Programmier-Modell ändert Zuweisungen sind eine fundamentale Änderung unseres Programmiermodells! Wichtige Invarianten (referentielle Transparenz, Konfluenz), an die wir uns gewöhnt haben, gelten nicht mehr Plötzlich wird die Zeit zum entscheidender Faktor! –Der Zeitpunkt vor einer Zuweisung im Vergleich zum Zeitpunkt nach einer Zuweisung –Auswertungsreihenfolge wird entscheidend (keine Konfluenz mehr gegeben) Plötzlich haben wir den Begriff der Identität! –Wir können zwei Adressbücher AB1 und AB2 haben, welche zu einem Zeitpunkt t 1 den gleichen Inhalt haben, aber zu einem anderen Zeitpunkt t 2 unterschiedlich sind –Das bedeutet, selbst wenn sie den gleichen Inhalt haben, sind es immer noch unterschiedliche Objekte: Sie haben eine Identität, zusätzlich zu ihrem momentanen Wert 14

15 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Sequenzieren von Auswertungen von Ausdrücken Angenommen, increment-counter soll nicht nur den aktuellen Wert des Zählers herausgeben, sondern diesen auch erhöhen Wie kombinieren wir die Ausdrücke der Zuweisung und des Zähler- Wertes? Wir könnten eine Kombinations-Funktion definieren, die zwei Parameter verarbeitet und den ersten ignoriert: (define (combine x y) y) Weil dieses Muster so gebräuchlich ist, gibt es eine spezielle Form für das Sequenzieren: (begin exp-1... exp-n exp) –Wertet exp-1 bis exp-n und exp in gegebener Reihenfolge aus –Liefert den Wert von exp 15 (define (increment-counter) … (set! counter-value (succ counter-value)) … … counter-value … )

16 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Ausdrucks-Auswertungen sequenzieren begin-Ausdrücke verwenden Der begin-Ausdruck ist nutzlos, wenn exp-1 … exp-n keine Nebeneffekte verursachen! Die Auswertungsreihenfolge ist wichtig: –Wenn x vor dem set!-Ausdruck ausgewertet würde, wäre das Ergebnis 3, und nicht 5 –Wir können eine Variable nicht länger durch ihren Wert ersetzen (z.B. x durch 3), weil sich ihr Wert ändern kann Keine referentielle Transparenz Durch das Ändern einer Definition zerstört eine Zuweisung den momentanen Wert. Wenn der Programmierer die Reihenfolge von Zuweisungen nicht sorgfältig festlegt, kann das fatal sein. 16 (define (increment-counter) (begin (set! counter-value (add1 counter-value)) counter-value)) (define x 3) (begin (set! x (+ x 2)) x)

17 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Eingabe/Ausgabe ist eine andere Art von Effekt Zuweisungen sind nur eine (wichtige) Art von Effekten Eine andere Art ist die Eingabe und Ausgabe (E/A bzw. I/O) –E/A ist jede Art von Kommunikation mit der externen Welt außerhalb des Programms Benutzereingaben (Maus, Tastatur, …) Eingaben von anderen Computern (z.B. per Netzwerk) Ausgabe (Bildschirm, Drucker, Steuergeräte, …) Wie die Zuweisungen ist auch E/A kein Teil des rein funktionalen Verhaltens einer Prozedur Die Reihenfolge von E/A-Effekten ist entscheidend –Etwa die Reihenfolge, in der Seiten gedruckt werden oder in der Motoren einer Maschine an- und ausgeschaltet werden 17

18 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Eingabe/Ausgabe ist eine andere Art von Effekt Nehmen Sie das Beispiel der folgenden E/A Funktion –draw-circle etc. Weil wir bisher nicht viel über Sequenzen und Effekte wussten, missbrauchten wir die and -Funktion um die Effekte zu sequenzieren –(and (draw-circle (make-posn 50 50) 100 yellow)) (draw-circle (make-posn 30 30) 100 green))) Durch die Nutzung von begin werden die Effekte besser sequenziert –(begin (draw-circle (make-posn 50 50) 100 yellow)) (draw-circle (make-posn 30 30) 100 green))) 18

19 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Einige Standard E/A-Funktionen Ausgabe des Parameters nach stdout –Als Wert nach stdout : print : any -> void –Ohne Hochkomma an Symbolen und Strings etc.: display : any -> void –Traditionelle Art, irgendwo zwischen print und display: write : any -> void –Wie write, aber mit automatischem Zeilenumbruch und Einrückung: pretty-print : any -> void –Formatierung der restlichen Argumente passend zum ersten: printf : string any... -> void –Ausgabe eines Zeilenumbruchs: newline : -> void Lesen von Eingaben vom Benutzer: read : -> sexp 19 (begin (printf "Enter your name:") (printf "Hello ~v" (read))) Beispiel:

20 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Ändern von lokalen Werten Wir können jeden definierten ( define ) Namen ändern –Nicht nur globale, sondern auch lokale Definitionen Weil lokale Definitionen einmal pro Aufruf der entsprechenden Prozedur verfügbar sind, haben wir eine dynamische und unbegrenzte Anzahl von Variablen Beispiel: Zähler mit lokalen Variablen 20 (define (make-counter init) (local ((define counter-value init)) (lambda () (begin (set! counter-value (succ counter-value)) counter-value)))) (define c1 (make-counter 0)) (define c2 (make-counter 0)) (c1) 1 (c1) 2 (c1) 3 (c2) 1 (c2) 2

21 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Ändern von lokalen Werten Die Anzahl von Zählern ist unbegrenzt –Beispiel: 500 Zähler erstellen Das wäre mit globalen Variablen nicht möglich –Die Anzahl von globalen Variablen ist konstant! 21 (define list-of-counters (build-list 500 (lambda (n) (make-counter 0))))

22 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Entwerfen von Funktionen mit Gedächtnis Wie beeinflussen Zuweisungen unseren Entwurfsprozess? Zustandsvariablen sollten immer eine Zweckbeschreibung (purpose statement) an der Stelle haben, an der sie definiert und initialisiert werden Wenn eine Funktion einen Effekt hat, sollte ihr Effekt beschrieben werden 22 ;; State Variable: ;; address-book : (listof (list symbol number)) ;; to keep track of pairs of names and phone numbers (define address-book empty) ;; add-to-address-book : symbol number -> void ;; Purpose: the function always produces (void) ;; Effect: to add (list name phone) to the ;; front of address-book

23 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Entwerfen von Funktionen mit Gedächtnis Das Zusammenstellen von Beispielen wird schwieriger –Die Zeitpunkte müssen mit einbezogen werden Gleichermaßen werden Tests schwieriger 23 ;; Examples: ;; if address-book is empty and we evaluate ;; (add-to-address-book 'Adam 1), ;; address-book is (list (list 'Adam 1)). ;; ;; if address-book is (list (list 'Eve 2)) and we evaluate ;; (add-to-address-book 'Adam 1), ;; address-book is (list (list 'Adam 1) (list 'Eve 2)). ;; ;; if address-book is (list E-1... E-2) and we evaluate ;; (add-to-address-book 'Adam 1), ;; address-book is (list (list 'Adam 1) E-1... E-2). ;; Tests: (begin (set! address-book empty) (add-to-address-book 'Adam 1) (equal? '((Adam 1)) address-book))

24 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Sind Zustandsvariablen nötig? Gibt es Programme, die nicht ohne Zuweisungen geschrieben werden können? –Nein! Jedes Programm mit Zuweisungen kann in ein äquivalentes Programm ohne Zuweisungen umgeschrieben werden Beispiel: Die Implementierung für lookup/add-to-address-book kann dieselbe sein wie lookup/add für maps 24 ;; lookup : symbol addressbook -> number or false ;; to lookup the number associated with name in ADDRESS-BOOK ;; if it doesn't find name, the function produces false (define (lookup name ab)...) ;; add-to-address-book : symbol number addressbook -> address-book ;; to add name and number to address-book (define (add-to-address-book name number ab)...) (lookup dawn (add-to-address-book dawn 123 empty))

25 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Sind Zustandsvariablen nötig? Der Unterschied zwischen den beiden Versionen ist, dass der Aufrufer das Adressbuch kennen und es im Auge behalten muss Wenn es viele unterschiedliche Aufrufer gibt, die sich dasselbe Adressbuch teilen sollen, kann das schwierig werden Zustandsvariablen können simuliert werden, indem jede Funktion umgeschrieben wird, um ein Zustandsobjekt als zusätzlichen Parameter zu verarbeiten und ein (möglicherweise unterschiedliches) Zustandsobjekt als zusätzlichen Rückgabewert zurück zu liefern –Das Zustandsobjekt repräsentiert den momentanen Zustand der Welt - die Werte aller Zustandsvariablen –Eine Funktion, die einem Wert etwas zuweisen möchte, kann ein anderes Zustandsobjekt zurückgeben 25

26 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Sind Zustandsvariablen nötig? Das Zustandsobjekt wird dann durch das Programm gereicht Zum Beispiel könnte (f (g 42) (h 23)) wie folgt sein für (define-struct result (value state) Beachten Sie, wie dieses Programm eine Auswertungsreihenfolge von links nach rechts etabliert! Diese Simulation ist sehr raffiniert, weil sie für jedes Programm mit Zustand funktioniert Für die meisten speziellen Programme ist es weitaus weniger schmerzvoll, Zustandsvariablen loszuwerden 26 (local ((define r1 (g 42 current-state)) (define r2 (h 23 (result-state r1)))) (f (result-value r1) (result-value r2) (result-state r2)))

27 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zustandsvariablen als Kommunikationskanäle Variablen ermöglichen eine neue Möglichkeit der Kommunikation in Programmen Ohne Zustandsvariablen erfolgt jegliche Kommunikation durch Prozedur-Parameter und deren Ergebnisse Mit Zustandsvariablen können verschiedene Programmteile, die auf eine gemeinsam benutze Zustandsvariable zugreifen, Informationen durch die Variable austauschen! –Eine Zustandsvariable ist ein Kommunikationskanal! 27

28 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zustandsvariablen und Black Boxes Die Idee einer Prozedur als Black-Box ist es, Details über ihre Implementierung zu verbergen –Aufrufende müssen nur ihre Schnittstelle kennen Mit Zustandsvariablen wird die Schnittstelle komplexer –Es ist schwierig vorauszusagen, welche Variablen geändert werden –Änderungen an Variablen sind im Vertrag der Funktion nicht sichtbar Benutzen Sie niemals (!!!) globale Zustandsvariablen, um Informationen von einem Funktionsaufruf zur Funktionsdefinition oder umgekehrt zu transferieren Allgemein: Immer wenn Informationen genau so gut durch Funktionsparameter/Rückgabewerte übergeben werden können, benutzen Sie Funktionsparameter/Rückgabewerte und nicht Zustandsvariablen 28

29 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zuweisungen und Performanz In manchen Fällen kann Performanz ein Grund für Zuweisungen sein Zuweisungen können sehr effizient auf typischer Hardware implementiert werden (so genannte von Neumann Architektur) Das Ändern eines großen zusammengesetzten Werts (z.B. großer Baum/lange Liste) kann sehr teuer sein, wenn er in einem rein funktionalen Stil geändert wird Auf der anderen Seite kann so ein zusammengesetzter Wert normalerweise auf eine nicht-funktionale (destruktive) Art in konstanter Zeit modifiziert werden 29

30 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zuweisungen und Streams Streams sind manchmal eine gute Alternative zu Zuweisungen –Wir modellieren das zeitabhängige Verhalten durch einen Stream Beispiel: Zufallszahlen –Wir haben eine initiale Zufallszahl random-init –Wir haben eine Funktion, die aus der vorherigen Zufallszahl die nächste Zufallszahl berechnet: rand-update 30 Version mit einem Stream (define random-numbers (my-cons random-init (map rand-update random-numbers))) (define rand (local ((define x random-init)) (lambda () (begin (set! x (rand-update x)) x)))) Version mit Zuweisung

31 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zustandsvariablen: The Good, the Bad and the Ugly Zustandsvariablen bevorzugen Freiheit von Kommunikation zu Lasten von Sicherheit und Vorhersehbarkeit Zuweisungen sind nicht per se gut oder schlecht (oder häßlich) –Sie können ein extrem mächtiges Werkzeug sein Modularität und Performanz –Aber sie machen das Programm auch weniger verständlich und vorhersehbar Keine Konfluenz, keine referentielle Transparenz, implizit verborgene (möglicherweise unbeabsichtigte) Kommunikation, … Sie sollten sich dieser impliziten Kosten der Benutzung von Zuweisungen bewusst sein! Merken Sie sich, dass jedes Programm ohne Zuweisungen geschrieben werden kann Eine gute Daumenregel ist, dass Sie viel weniger Zuweisungen benötigen, als Sie denken! 31

32 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T10 Zustandsvariablen: The Good, the Bad and the Ugly Eine Warnung an jene, die bereits Erfahrungen mit irgendeiner Programmiersprache gemacht haben: –Verfallen Sie nicht zurück in alte (schlechte) Angewohnheiten! –Fühlen Sie sich nicht zu sicher, weil Sie nun die Mechanismen kennen, die Sie immer angewendet haben. –Betrachten Sie Berechnungen nicht hauptsächlich als Abfolge von Berechnungs- und Zuweisungsschritten! Das skaliert nicht für große Programme Denken Sie eher in Kategorien der Problemzerlegung und Problemkomposition Zuweisungen werden in dieser Vorlesung u. a. deshalb erst so spät eingeführt, damit Sie diese Denkweise ablegen. 32


Herunterladen ppt "Telecooperation/RBG Technische Universität Darmstadt Copyrighted material; for TUD student use only Grundlagen der Informatik 1 Thema 10: Zuweisungen und."

Ähnliche Präsentationen


Google-Anzeigen