Pregunta

Estoy siguiendo Estructura e Interpretación de los Programas de Ordenador y al intentar resolver Ex 1.3 llegué en el código siguiente como mi primer intento:

(define (sumsq a b c)(
(define highest (if (> (if (> a b) a b) (if (> a c) a c)) (if (> a b) a b) (if (> a c) a c)))
(define second_h (if (> (if (> a b) b a) (if (> a c) c a)) (if (> a b) b a) (if (> a c) c a)))
(+ (* highest highest) (* second_h second_h)))

No fue a trabajar y yo busqué la solución y la encontré en SICP Wiki

;; ex 1.3
;; implemented using only techniques covered to this point

(define (square x) (* x x))

(define (sum-of-squares x y)
  (+ (square x) (square y)))

(define (largest-two-of-three x y z)
  (if (>= x y)
      (sum-of-squares x (if (>= y z) y z))
      (sum-of-squares y (if (>= x z) x z))))

La diferencia era que yo estaba usando múltiples declaraciones a la definición de las variables y, a continuación, suma de cuadrados, mientras que la forma correcta es definir cada una de mis líneas como funciones.

Son funciones en el Esquema de los trazadores de líneas uno?O no me pierda toda la cosa?

¿Fue útil?

Solución

Lo que escribió (menos uno extra paréntesis) es:

(define (sumsq a b c)
  (define highest
    (if (> (if (> a b) a b)
           (if (> a c) a c))
      (if (> a b) a b)
      (if (> a c) a c)))
  (define second_h
    (if (> (if (> a b) b a)
           (if (> a c) c a))
      (if (> a b) b a)
      (if (> a c) c a)))
  (+ (* highest highest) (* second_h second_h)))

Su solución separan cuadrados y la suma de cuadrados en funciones separadas, pero no creo que eso es lo importante.No escribir (+ (* a a) (* b b)) se dejar de tener a nombre de los dos valores que se está calculando, que te permitirá escribir la función como una gran expresión en la final, pero hay más cosas de las que preocuparse ahora.

Creo que el problema que tienes es que tu (si...) las expresiones son demasiado grandes para entender fácilmente.Observe que hay dos patrones que se muestran muchas veces: (if (> a b) a b) y (if (> a b) b a).Estas son las funciones max y min, lo que es útil para los definen como tales:

(define (min a b) (if (< a b) a b))
(define (max a b) (if (< a b) b a))

De esta manera, usted puede volver a escribir la solución como:

(define (sumsq a b c)
  (define highest
    (if (> (max a b) (max a c))
      (max a b)
      (max a c)))
  (define second_h
    (if (> (min a b) (min a c))
      (min a b)
      (min a c)))
  (+ (* highest highest) (* second_h second_h)))

La simplificación de que de nuevo da:

(define (sumsq a b c)
  (define highest
    (max (max a b) (max a c)))
  (define second_h
    (max (min a b) (min a c)))
  (+ (* highest highest) (* second_h second_h)))

Observe cómo esta escritura es mucho más fácil razonar con el, (max (max a b) (max a c)) es, obviamente, el máximo de a b y c, y en realidad puede ser reescrita como (max (max a b) c).Mirando second_h, sin embargo, no es obvio de que es correcta.Qué va a pasar cuando a es el más pequeño de los tres valores?

El truco que utilizan en su solución es el primero comparar x y y.si x < y, entonces usted sabe que y no es el más pequeño de los tres, por lo que es alta o la segunda más alta.El número que usted desea utilizar es el mayor de x y z, desde el menor de los dos será el más pequeño de los tres, el que desea ignorar.Una lógica Similar se aplica cuando y < x.

Otros consejos

Debe usar sangría y saltos de línea adecuados para obtener una visión general sobre el flujo de su programa. Su primera propuesta se lee así:

(define (sumsq a b c)
  ((define highest 
     (if (> (if (> a b) a b)
            (if (> a c) a c))
         (if (> a b) a b)
         (if (> a c) a c)))
   (define second-h
     (if (> (if (> a b) b a)
            (if (> a c) c a))
         (if (> a b) b a)
         (if (> a c) c a)))
   (+ (* highest highest)
      (* second-h second-h)))

Lo primero que debe notar: los paréntesis no coinciden; hay uno más abierto que cerrado. Una inspección cuidadosa muestra que un paréntesis de apertura en la segunda línea está mal. Este es, por cierto, el que colgaba de alguna manera al final de su primera línea. Me arriesgaría a suponer que cuando trataste de evaluar esto, no pasó nada, ya que el lector esperó el final de la declaración.

La sangría adecuada es bastante importante. Creo que SICP no lo explica explícitamente, aunque los ejemplos generalmente se hacen de esta manera. Encontré una guía de estilo aquí .

Segunda observación: te repites mucho. En todas esas declaraciones if anidadas, no estoy realmente seguro de si realmente obtuviste los valores correctos. Mire la solución que encontró para ver cómo esto se puede simplificar enormemente.

Intentaste romper la complejidad dando nombres de subresultados. Romper la complejidad es bueno, pero generalmente es mejor nombrar no los resultados, sino los conceptos. Piensa en lo que haces, luego nombra estas actividades. Esas son funciones, y constituyen el lenguaje en el que finalmente resuelves tu problema casi trivialmente.

Una de las ideas de Scheme es bottom-up programming donde se crea una función para cada operación conceptual. Ese es el enfoque recomendado en muchos lenguajes de programación funcionales.

Con este enfoque, termina con muchas funciones pequeñas que implementan una operación lógica en los argumentos. De esa forma, su código termina siendo mucho más modular y limpio.

Su solución tenía esta forma: (define (func param) (define ...) (define ...))

Pero define necesita esta forma: (define (func param) body)

El cuerpo es la implementación de la función ... lo que hace, lo que devuelve. Tu cuerpo era solo más definiciones, nunca hacía nada. Eso explica por qué su solución no fue aceptada por el intérprete de Scheme.

Para responder a la pregunta " ¿son las funciones del esquema de una sola línea? " necesita investigar el " comenzar " forma, que se ve así: (comenzar (+ 1 1) (+ 2 2)) = > 4

En el ejemplo anterior, el resultado de (+ 1 1) simplemente se arroja, por lo que puede ver que comenzar solo tiene sentido cuando las cosas dentro de él tienen efectos secundarios.

Debe tener en cuenta que algunas partes de Scheme (especialmente let y lambda) tienen comienzos implícitos alrededor de su cuerpo. Entonces esto es válido:

  (let ((x 1))
    (+ 1 1)
    (+ 2 2))

incluso sin un comienzo. Esto hace que el código sea más sencillo de escribir.

Finalmente, a medida que continúa aprendiendo Esquema, siempre trate de encontrar una manera de hacer algo sin comienzos y sin efectos secundarios. Especialmente en los primeros capítulos de la mayoría de los libros de Scheme, si estás pensando, & "; Quiero establecer esa variable, entonces quiero hacer esto, entonces esto ... &"; probablemente esté atrapado en su antigua forma de programación y no lo haga de la manera Scheme. No hay nada de malo en los efectos secundarios, pero el uso intensivo de ellos significa que realmente no estás programando Scheme de la manera que funciona mejor.

Ejercicio 1.3 pide definir un procedimiento que dura tres números como argumentos y devuelve la suma de los cuadrados de los dos números más grandes.Es fácil de definir un procedimiento como el que el uso de la incorporada en el Esquema de los procedimientos de square, max, y min, pero no hemos encontrado estos procedimientos en ese punto en el libro, así que me gustaría definir como bien.

(define (square x)
   (* x x))

(define (max x y)
   (if (> x y) x y))

(define (min x y)
   (if (< x y) x y))

(define (sum-of-highest-squares x y z)
   (+ (square (max x y))
      (square (max (min x y) z))))

El sum-of-highest-squares procedimiento funciona mediante la adición de la plaza de el máximo de x e y (el máximo de los dos es eliminado de ser la más baja de los tres) y el cuadrado de la máxima de las dos restantes (el mínimo de x y y, que será el valor se dejó el primer paso), y z.

Nota:Esto es de mi blog SICP Ejercicios 1.1 - 1.5.Hay enlaces que le llevarán a muchos de los otros SICP soluciones de allí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top