scheme sicp

scheme - Petición del ejercicio 1.3 del SICP para comentarios



(16)

Estoy tratando de aprender el esquema a través de SICP. El ejercicio 1.3 dice lo siguiente: Defina un procedimiento que tome tres números como argumentos y devuelva la suma de los cuadrados de los dos números más grandes. Comente 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))))))


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

Mi enfoque es diferente. En lugar de muchas pruebas, simplemente agrego los cuadrados de los tres, luego restamos 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 usted prefiere este enfoque, o un montón de pruebas, depende de usted, por supuesto.

Implementación alternativa usando 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 línea (gracias synx @ freenode #scheme); también requiere SRFI 1 y SRFI 26 :

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


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


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 esto (proc p) se puede convertir fácilmente para manejar cualquier cantidad de argumentos.


¿Qué tal algo así?

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


Lo hice con el siguiente código, que usa los procedimientos min , max y square incorporados. Son lo suficientemente simples como para implementar utilizando 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))))


Con Scott Hoffman''s y algo de IRC ayuda, 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))) (else (+ (square b) (square 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)))))


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


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


(define (f a b c) (if (= a (min a b c)) (+ (* b b) (* c c)) (f b c a)))


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


Creo que esta es la forma más pequeña y más 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 sobre 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))


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