2010-12-30 12 views
5

En el ejercicio de htdp 01/18/12, he re-escrito usando la función maxi "local".El uso de local en raqueta/Esquema

;; 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))]))])) 

no estoy seguro de por qué me gustaría hacer esto en la "vida real", ya que parece la versión del libro es más corto, más clara y probablemente más rápido también.

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

¿Fue destinado a ser un ejercicio puramente pedagógica? ¿Podría Schemer con experiencia comentar sobre el código anterior? Gracias.

+0

Bueno, aquí hay una [pregunta socrática] (http://en.wikipedia.org/wiki/Socratic_questioning) para ti: ¿Por qué crees que la versión no 'local' es" probablemente más rápida "? Voy a publicar una respuesta real a esta pregunta después de escuchar tus pensamientos. :-) –

+0

Sifu Chris, gracias por preguntar mis suposiciones ASS. Estoy aprendiendo a apreciar tu visión más y más. Así que parece que la versión "local" es mucho más rápida que la versión recursiva "pura" cuando la lista es grande. Llegué a esta conclusión llamando a la función de tiempo en una lista con 20 números y me asombró ver una diferencia promedio de 550 veces en el rendimiento. Sin embargo, no sé cómo funciona Racket/Scheme internamente para explicar la discrepancia. Pasar por la versión "local" parece mostrar que 20 versiones de la función local "m" están produciendo un valor. – Greenhorn

Respuesta

3

Personalmente, creo que este es un pobre ejemplo de la importancia de local y no creo que haya entendido completamente la importancia de la pregunta, entonces lo que haré es pasar por el concepto que debe notar, luego vaya a través de tu ejemplo y finalmente darte un mejor ejemplo.

CONCEPTO

En primer lugar, la idea de local aquí (entre muchos otras cosas) es aclarar el significado de fragmentos de código.

SU EJEMPLO

Vamos a considerar su ejemplo, se define una constante local llamado m que parece ser correcta. Aunque, dado que la letra m no tiene un significado significativo, su solución parece no estar clara. Entonces, ¿cómo podríamos solucionar tu solución?

Tenemos que dar m un nombre que identifica claramentem lo que representa. Por lo tanto, comenzamos por considerar directamente lo m representa que es (maxi (rest alon))

Bueno (maxi (rest alon)) dice simplemente encontrar el número máximo de (rest alon)

lo tanto, permite cambiar el nombre de m a find-max

Ahora su código es el siguiente:

;; 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))]))])) 

Sustitución m con find-max hace que el código mucho más claro! Dejándonos con una regla de , proporcione a sus constantes nombres significativos.

mi ejemplo

Para aclarar aún más, consideremos una función que consume dos puntos y produce la pendiente del segmento de línea creado mediante la conexión de los dos puntos. Nuestro primer enfoque podría ser:

;;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)))) 

Pero podría ser más claro usando 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)))) 

Observe cómo delta describe lo que hace la función de esa parte; encontrando el cambio en x o y. Entonces, lo que tenemos que aprender aquí es que, aunque la primera solución puede utilizar menos código, la segunda solución describe lo que estamos haciendo y puede leerse fácilmente.Esa fue toda la idea de la pregunta y puede parecer estúpida, pero es una convención que tienden a enfatizar al aprender el esquema en un entorno académico.

En cuanto a la eficacia de la primera y segunda solución, la segunda solución es definitivamente mucho más rápida por razones obvias (después de ver cómo Racket evalúa expresiones), pero ese no era el objetivo principal de la pregunta.

Esperanza esto ayuda

+0

¡Gracias Adrian por tomarte el tiempo para explicar las cosas con claridad! Estoy en deuda con usted – Greenhorn

+0

No hay problema - me complace ayudarlo. –

3

En lugar de utilizar local, uno puede ir tan bien con las definiciones internas de Raqueta (especialmente con las versiones más recientes).

Por ejemplo:

(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

Tenga en cuenta que las definiciones internas (a propósito) no están disponibles en los idiomas de enseñanza. Para enfatizar que las definiciones son locales, uno tiene que usar 'local'. – soegaard

0

Usando local es mucho más rápido, ya que aquí sólo se evalúa una vez por (maxi (rest alon)) recursividad, mientras que con la segunda versión se evalúa (maxi (rest alon)) dos veces cada vez que se llega al último caso.

Local guarda el resultado para que no haga el mismo trabajo dos veces.

Cuestiones relacionadas