Pregunta

Estoy tratando de aprender el esquema a través de SICP. El ejercicio 1.3 dice lo siguiente: Defina un procedimiento que toma tres números como argumentos y devuelve la suma de los cuadrados de los dos números más grandes. Por favor, comenta sobre cómo puedo mejorar mi solución.

(define (big x y)
    (if (> x y) x y))

(define (p a b c)
    (cond ((> a b) (+ (square a) (square (big b c))))
          (else (+ (square b) (square (big a c))))))
¿Fue útil?

Solución

Me parece bien, ¿hay algo específico que quieras mejorar?

Podrías hacer algo como:

(define (max2 . l)
  (lambda ()
    (let ((a (apply max l)))
      (values a (apply max (remv a l))))))

(define (q a b c)
  (call-with-values (max2 a b c)
    (lambda (a b)
      (+ (* a a) (* b b)))))

(define (skip-min . l)
  (lambda ()
    (apply values (remv (apply min l) l))))

(define (p a b c)
  (call-with-values (skip-min a b c)
    (lambda (a b)
      (+ (* a a) (* b b)))))

Y este (proc p) se puede convertir fácilmente para manejar cualquier número de argumentos.

Otros consejos

Usando solo los conceptos presentados en ese punto del libro, lo haría:

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

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

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

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

(define (sum-squares-2-biggest x y z)
  (sum-of-squares (max x y) (max z (min x y))))

big se llama max . Utilice la funcionalidad de biblioteca estándar cuando esté allí.

Mi enfoque es diferente. En lugar de un montón de pruebas, simplemente agrego los cuadrados de los tres, luego resto el cuadrado del más pequeño.

(define (exercise1.3 a b c)
  (let ((smallest (min a b c))
        (square (lambda (x) (* x x))))
    (+ (square a) (square b) (square c) (- (square smallest)))))

Si prefiere este enfoque, o un grupo de pruebas de if , depende de usted, por supuesto.


Implementación alternativa utilizando SRFI 95 :

(define (exercise1.3 . args)
  (let ((sorted (sort! args >))
        (square (lambda (x) (* x x))))
    (+ (square (car sorted)) (square (cadr sorted)))))

Como arriba, pero como una sola línea (gracias a synx @ freenode #scheme); también requiere SRFI 1 y SRFI 26 :

(define (exercise1.3 . args)
  (apply + (map! (cut expt <> 2) (take! (sort! args >) 2))))

Lo hice con el siguiente código, que utiliza los procedimientos integrados min , max y square . Son lo suficientemente simples para implementar usando solo lo que se ha introducido en el texto hasta ese momento.

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

¿Qué pasa con algo como esto?

(define (p a b c)
  (if (> a b)
      (if (> b c)
          (+ (square a) (square b))
          (+ (square a) (square c)))
      (if (> a c)
          (+ (square a) (square b))
          (+ (square b) (square c)))))

Usando solo los conceptos introducidos hasta ese punto del texto, que creo que es bastante importante , aquí hay una solución diferente:

(define (smallest-of-three a b c)
        (if (< a b)
            (if (< a c) a c)
            (if (< b c) b c)))

(define (square a)
        (* a a))

(define (sum-of-squares-largest a b c) 
        (+ (square a)
           (square b)
           (square c)
           (- (square (smallest-of-three a b c)))))
(define (sum-sqr x y)
(+ (square x) (square y)))

(define (sum-squares-2-of-3 x y z)
    (cond ((and (<= x y) (<= x z)) (sum-sqr y z))
             ((and (<= y x) (<= y z)) (sum-sqr x z))
             ((and (<= z x) (<= z y)) (sum-sqr x y))))
(define (f a b c) 
  (if (= a (min a b c)) 
      (+ (* b b) (* c c)) 
      (f b c a)))

Con Scott Hoffman y alguna ayuda de irc, corregí mi código defectuoso, aquí está

(define (p a b c)
    (cond ((> a b)
        (cond ((> b c)
            (+ (square a) (square b)))
            (else (+ (square a) (square c)))))
        (else
            (cond ((> a c)
                (+ (square b) (square a))))
             (+ (square b) (square c)))))

También puede ordenar la lista y agregar los cuadrados del primer y segundo elemento de la lista ordenada:

(require (lib "list.ss")) ;; I use PLT Scheme

(define (exercise-1-3 a b c)
  (let* [(sorted-list (sort (list a b c) >))
         (x (first sorted-list))
         (y (second sorted-list))]
    (+ (* x x) (* y y))))

Aquí hay otra forma de hacerlo:

#!/usr/bin/env mzscheme
#lang scheme/load

(module ex-1.3 scheme/base
  (define (ex-1.3 a b c)
    (let* ((square (lambda (x) (* x x)))
           (p (lambda (a b c) (+ (square a) (square (if (> b c) b c))))))
      (if (> a b) (p a b c) (p b a c))))

  (require scheme/contract)
  (provide/contract [ex-1.3 (-> number? number? number? number?)]))

;; tests
(module ex-1.3/test scheme/base
  (require (planet "test.ss" ("schematics" "schemeunit.plt" 2))
           (planet "text-ui.ss" ("schematics" "schemeunit.plt" 2)))
  (require 'ex-1.3)

  (test/text-ui
   (test-suite
    "ex-1.3"
    (test-equal? "1 2 3" (ex-1.3 1 2 3) 13)
    (test-equal? "2 1 3" (ex-1.3 2 1 3) 13)
    (test-equal? "2 1. 3.5" (ex-1.3 2 1. 3.5) 16.25)
    (test-equal? "-2 -10. 3.5" (ex-1.3 -2 -10. 3.5) 16.25)
    (test-exn "2+1i 0 0" exn:fail:contract? (lambda () (ex-1.3 2+1i 0 0)))
    (test-equal? "all equal" (ex-1.3 3 3 3) 18))))

(require 'ex-1.3/test)

Ejemplo:

$ mzscheme ex-1.3.ss
6 success(es) 0 failure(s) 0 error(s) 6 test(s) run
0

Es bueno ver cómo otras personas han resuelto este problema. Esta fue mi solución:

(define (isGreater? x y z)
(if (and (> x z) (> y z))
(+ (square x) (square y))
0))

(define (sumLarger x y z)
(if (= (isGreater? x y z) 0)   
(sumLarger y z x)
(isGreater? x y z)))

Lo resolví por iteración, pero me gustan las soluciones de ashitaka y (+ (cuadrado (max xy)) (square (max (min xy) z))), ya que en mi versión, si z es el número más pequeño , ¿es mayor? Se llama dos veces, creando un procedimiento innecesariamente lento y tortuoso.

(define (sum a b) (+ a b))
(define (square a) (* a a))
(define (greater a b ) 
  ( if (< a b) b a))
(define (smaller a b ) 
  ( if (< a b) a b))
(define (sumOfSquare a b)
    (sum (square a) (square b)))
(define (sumOfSquareOfGreaterNumbers a b c)
  (sumOfSquare (greater a b) (greater (smaller a b) c)))

He tenido una oportunidad:

(define (procedure a b c)
    (let ((y (sort (list a b c) >)) (square (lambda (x) (* x x))))
        (+ (square (first y)) (square(second y)))))
;exercise 1.3
(define (sum-square-of-max a b c)
  (+ (if (> a b) (* a a) (* b b))
     (if (> b c) (* b b) (* c c))))

Creo que esta es la forma más pequeña y eficiente:

(define (square-sum-larger a b c)
 (+ 
  (square (max a b))
  (square (max (min a b) c))))

A continuación se muestra la solución que se me ocurrió. Me resulta más fácil razonar acerca de una solución cuando el código se descompone en pequeñas funciones.

            ; Exercise 1.3
(define (sum-square-largest a b c)
  (+ (square (greatest a b))
     (square (greatest (least a b) c))))

(define (greatest a b)
  (cond (( > a b) a)
    (( < a b) b)))

(define (least a b)
  (cond ((> a b) b)
    ((< a b) a)))

(define (square a)
  (* a a))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top