Question

J'essaie d'apprendre les schémas via le SICP. L’exercice 1.3 se lit comme suit: Définissez une procédure utilisant trois nombres comme arguments et renvoyant la somme des carrés des deux plus grands nombres. Veuillez indiquer comment je peux améliorer ma solution.

(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))))))
Était-ce utile?

La solution

Ca me va, y a-t-il quelque chose de spécifique que vous souhaitez améliorer?

Vous pouvez faire quelque chose comme:

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

Et cela (proc p) peut être facilement converti pour gérer un nombre quelconque d'arguments.

Autres conseils

En utilisant uniquement les concepts présentés à ce stade du livre, je le ferais:

(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 est appelé max . Utilisez les fonctionnalités de la bibliothèque standard, le cas échéant.

Mon approche est différente. Plutôt que de nombreux tests, j’ajoute simplement les carrés des trois, puis soustrais le carré du plus petit.

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

Vous préférez bien sûr cette approche, ou un ensemble de tests si , à vous de choisir.

Implémentation alternative utilisant SRFI 95 :

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

Comme ci-dessus, mais en une couche (merci synx @ freenode #scheme); Il faut également SRFI 1 et SRFI 26 :

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

Je l'ai fait avec le code suivant, qui utilise les procédures intégrées min , max et carré . Ils sont assez simples à implémenter en utilisant uniquement ce qui a été introduit dans le texte jusqu’à maintenant.

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

Qu'en est-il de quelque chose comme ça?

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

En utilisant uniquement les concepts introduits jusqu'à ce point du texte, que je trouve plutôt important , voici une solution différente:

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

Avec l'aide de Scott Hoffman et de l'aide d'irc, j'ai corrigé mon code défectueux, le voici

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

Vous pouvez également trier la liste et ajouter les carrés des premier et deuxième éléments de la liste triée:

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

Voici encore un autre moyen de le faire:

#!/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)

Exemple:

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

Cela fait plaisir de voir comment d’autres personnes ont résolu ce problème. C'était ma solution:

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

Je l'ai résolu par itération, mais j'aime mieux les solutions d'ashitaka et (+ (carré (max xy)) (carré (max (min xy) z)), car dans ma version, si z est le plus petit nombre , est plus grand? est appelé deux fois, créant une procédure inutilement lente et détournée.

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

J'ai essayé:

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

Je pense que c'est le moyen le plus petit et le plus efficace:

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

Vous trouverez ci-dessous la solution que j'ai proposée. Je trouve plus facile de raisonner sur une solution lorsque le code est décomposé en petites fonctions.

            ; 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))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top