2010-12-30 1 views
5

In Übung 18.1.12 von htdp habe ich die Maxifunktion mit "local" umgeschrieben.Verwendung von local in Racket/Scheme

;; maxi : non-empty-lon -> number 
;; to determine the largest number on alon 
(define (maxi alon) 
    (cond 
    [(empty? (rest alon)) (first alon)] 
    [else (local ((define m (maxi (rest alon)))) 
      (cond 
       [(> (first alon) m) (first alon)] 
       [(> m (first (rest alon))) m] 
       [else (first (rest alon))]))])) 

Ich bin mir nicht sicher, warum ich dies tun würde im „wirklichen Leben“, wie es die Version des Buchs scheint kürzer, klarer und wahrscheinlich auch schneller.

(define (maxi alon) 
    (cond 
    [(empty? (rest alon)) (first alon)] 
    [else (cond 
     [(> (first alon) (maxi (rest alon))) (first alon)] 
     [else (maxi (rest alon))])])) 

War es eine rein pädagogische Übung? Könnte ein erfahrener Schemer den obigen Code kommentieren? Vielen Dank.

+0

Nun, hier ist eine [sokratische Frage] (http://en.wikipedia.org/wiki/Socratic_questioning) für Sie: Warum denken Sie, dass die nicht-lokale Version "wahrscheinlich schneller" ist? Ich werde eine echte Antwort auf diese Frage veröffentlichen, nachdem ich Ihre Gedanken gehört habe. :-) –

+0

Sifu Chris, danke, dass du meine ASS-Annahmen fragst. Ich lerne deine Einsicht immer mehr zu schätzen. So scheint es, dass die "lokale" Version viel schneller ist als die "reine" rekursive Version, wenn die Liste groß wird. Ich kam zu dieser Schlussfolgerung, indem ich die Zeitfunktion auf einer Liste mit 20 Zahlen anwendete und war erstaunt, einen Durchschnitt von 550 x Unterschied in der Leistung zu sehen. Ich weiß nicht, wie Racket/Scheme intern funktioniert, um die Diskrepanz zu erklären. Das Durchlaufen der "lokalen" Version scheint zu zeigen, dass 20 Versionen der lokalen Funktion "m" einen Wert erzeugen. – Greenhorn

Antwort

3

Persönlich denke ich, das ist ein schlechtes Beispiel für die Wichtigkeit von local und ich glaube nicht, dass Sie die Bedeutung der Frage vollständig verstanden, also was ich tun werde ist durch das Konzept gehen, das Sie beachten sollten, dann gehen durch dein Beispiel und schließlich ein besseres Beispiel.

CONCEPT

First off, hier die Idee der lokalen (unter viele anderem) ist die Bedeutung von Code-Schnipsel zu klären.

Ihr Beispiel

betrachten Ihr Beispiel Lets, definieren Sie eine lokale Konstante genannt m die richtige zu sein scheint. Obwohl der Buchstabe m keine signifikante Bedeutung hat, scheint Ihre Lösung unklar zu sein. Wie können wir Ihre Lösung reparieren?

Wir brauchen m einen Namen geben, dass eindeutig identifiziert, was m darstellt. So beginnen wir, indem Sie direkt zu überlegen, was m darstellt, die (maxi (rest alon)) ist

Nun (maxi (rest alon)) einfach sagt die maximale Anzahl von (rest alon)

finden So umbenennen können m-find-max

Jetzt Code wie folgt aussieht:

;; maxi : non-empty-lon -> number 
;; to determine the largest number on alon 
(define (maxi alon) 
    (cond 
    [(empty? (rest alon)) (first alon)] 
    [else (local ((define find-max (maxi (rest alon)))) 
      (cond 
       [(> (first alon) find-max) (first alon)] 
       [(> find-max (first (rest alon))) find-max] 
       [else (first (rest alon))]))])) 

Ersetzen m mit find-max macht den Code viel klarer! Verlassen Sie uns mit einer Faustregel, geben Sie Ihren Konstanten sinnvolle Namen.

MY BEISPIEL

Zur weiteren Klärung, können eine Funktion betrachten, die zwei Punkte verbraucht und produziert die Steigung des Liniensegments geschaffen, indem die beiden Punkte verbindet. Unser erster Ansatz könnte sein:

;;where x1,y1 belong to point 1 and x2,y2 belong to point 2 
(define (find-slope x1 y1 x2 y2) 
    (sqrt (+ (sqr (- x2 x1))) (sqr (- y2 y1)))) 

Aber wir könnten klarer sein mit local:

(define (find-slope x1 y1 x2 y2) 
    (local 
    [(define delta-x (- x2 x1)) 
    (define delta-y (- y2 y1))] 
    (sqrt (+ (sqr delta-x)) (sqr delta-y)))) 

Beachten Sie, wie Delta beschreibt, was die Funktion macht in diesem Teil; die Änderung in x oder y finden. Also, was wir hier lernen müssen ist, dass, obwohl die erste Lösung weniger Code verwenden kann, die zweite Lösung beschreibt, was wir tun und leicht gelesen werden kann.Das war die ganze Idee der Frage und es mag dumm erscheinen, aber es ist eine Konvention, die sie betonen, wenn sie in einem akademischen Umfeld lernen.

Für die Effizienz der ersten und zweiten Lösung, ist die zweite Lösung aus offensichtlichen Gründen (nachdem Sie sehen, wie Racket Ausdrücke bewertet) definitiv viel schneller, aber das war nicht der Hauptzweck der Frage.

this helps

+0

Danke Adrian, dass du dir Zeit genommen hast, die Dinge klar zu erklären! Ich bin in deiner Schuld. – Greenhorn

+0

Kein Problem - froh zu helfen. –

3

Statt local zu verwenden, kann man gehen auch Racket interne Definitionen (insbesondere mit neueren Versionen) verwenden.

Zum Beispiel:

(define (maxi alon) 
    (cond 
    [(empty? (rest alon)) (first alon)] 
    [else (define m (maxi (rest alon)))  ; here is an internal define 
      (cond 
      [(> (first alon) m) (first alon)] 
      [(> m (first (rest alon))) m] 
      [else (first (rest alon))])])) 
+2

Beachten Sie, dass interne Definitionen (absichtlich) in den Unterrichtssprachen nicht verfügbar sind. Um zu betonen, dass die Definitionen lokal sind, muss man "lokal" verwenden. – soegaard

0

lokale Verwendung ist Art und Weise hier schneller, weil es nur (maxi (rest alon)) einmal pro Rekursion auswertet, während bei der zweiten Version es (maxi (rest alon)) zweimal bewertet, wenn sie in den letzten Fall bekommen.

Local speichert das Ergebnis, sodass Sie nicht zweimal die gleiche Arbeit ausführen.