24

I'm trying to learn scheme via SICP. Exercise 1.3 reads as follow: Define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers. Please comment on how I can improve my 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))))))
ashitaka
  • 3,928
  • 7
  • 38
  • 43

17 Answers17

34

Using only the concepts presented at that point of the book, I would do it:

(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))))
Carlos Santos
  • 676
  • 5
  • 4
15

big is called max. Use standard library functionality when it's there.

My approach is different. Rather than lots of tests, I simply add the squares of all three, then subtract the square of the smallest one.

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

Whether you prefer this approach, or a bunch of if tests, is up to you, of course.


Alternative implementation using SRFI 95:

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

As above, but as a one-liner (thanks synx @ freenode #scheme); also requires SRFI 1 and SRFI 26:

(define (exercise1.3 . args)
  (apply + (map! (cut expt <> 2) (take! (sort! args >) 2))))
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • 1
    I think doing square is more expensive than a few extra tests. But that's just me :) – leppie Oct 02 '08 at 10:31
  • 5
    I think code should optimise clarity first, performance second. However, I'm willing to accept that reasonable people can disagree on this. :-) – C. K. Young Oct 02 '08 at 10:33
  • This is a very interesting solution. There's more than one way to skin the cat. – ashitaka Oct 02 '08 at 12:34
  • 1
    min, let, lambda, sort!, map!, cut car, cadr, take!, and apply are not yet introduced at that point in the text. – Shawn J. Goff Jan 09 '10 at 16:22
  • @Shawn: I didn't intend my solutions to be ones that people would implement on first reading, but rather what they might like to implement given a certain amount of Scheme experience. Besides, adventurous first readers might use such a solution as a basis for learning about parts of Scheme (and SRFIs) that aren't covered in the book. – C. K. Young Jan 09 '10 at 17:11
13

I did it with the following code, which uses the built-in min, max, and square procedures. They're simple enough to implement using only what's been introduced in the text up to that point.

(define (sum-of-highest-squares x y z)
   (+ (square (max x y))
      (square (max (min x y) z))))
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
12

What about something like this?

(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)))))
Scott Hoffman
  • 547
  • 7
  • 21
  • Voted up cause I was struggling on this and my code was on similar lines. I'm only learning and don't know yet the bigger constructs in the other examples. With your code I corrected my faulty one. Since I'm not able to add html code in here, I'm putting in my code in a separate reply below. – Christy John Dec 10 '09 at 14:10
6

Using only the concepts introduced up to that point of the text, which I think is rather important, here is a different solution:

(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)))))
Shawn J. Goff
  • 4,635
  • 8
  • 34
  • 38
5
(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))))
Scott Miao
  • 51
  • 1
  • 1
5
(define (f a b c) 
  (if (= a (min a b c)) 
      (+ (* b b) (* c c)) 
      (f b c a)))
user448810
  • 17,381
  • 4
  • 34
  • 59
4

Looks ok to me, is there anything specific you want to improve on?

You could do something like:

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

And this (proc p) can be easily converted to handle any number of arguments.

Svante
  • 50,694
  • 11
  • 78
  • 122
leppie
  • 115,091
  • 17
  • 196
  • 297
  • I believe the OP was asking for comments on style, and in that department there are some things that could be talked about, such as what's in my post. :-) – C. K. Young Oct 02 '08 at 10:29
  • P.S. I see you on #scheme (though you seem to keep getting logged out)! Small world! – C. K. Young Oct 02 '08 at 11:11
  • Yeah, seems my ISP is heavily shaping traffic on some ports. Funny thing is, I can send data, it just takes ages to receive anything :( That said, I didnt know the world had more than 100 Scheme users! hehe – leppie Oct 02 '08 at 11:31
  • Bummer about your ISP. Yes, it's nice to know there's a good handful of Schemers out here on the Internet.... :-) – C. K. Young Oct 02 '08 at 11:40
  • I'm a total newbie to scheme, so it's great to see your alternative solution (which is way over my head). – ashitaka Oct 02 '08 at 12:32
3

With Scott Hoffman's and some irc help I corrected my faulty code, here it is

(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)))))
GAD3R
  • 4,317
  • 1
  • 23
  • 34
Christy John
  • 680
  • 6
  • 17
2

You can also sort the list and add the squares of the first and second element of the sorted list:

(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))))
Sébastien RoccaSerra
  • 16,731
  • 8
  • 50
  • 54
  • Sébastien, I haven't learnt yet how to work with lists; but again an interesting solution. I am using PLT-scheme. Will that require work on PLT-scheme ? – ashitaka Oct 02 '08 at 12:37
2

It's nice to see how other people have solved this problem. This was my 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)))

I solved it by iteration, but I like ashitaka's and the (+ (square (max x y)) (square (max (min x y) z))) solutions better, since in my version, if z is the smallest number, isGreater? is called twice, creating an unnecessarily slow and circuitous procedure.

2

Here's yet another way to do it:

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

Example:

$ mzscheme ex-1.3.ss
6 success(es) 0 failure(s) 0 error(s) 6 test(s) run
0
jfs
  • 399,953
  • 195
  • 994
  • 1,670
1
(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)))
riddhi_agrawal
  • 215
  • 2
  • 8
0

I've had a go:

(define (procedure a b c)
    (let ((y (sort (list a b c) >)) (square (lambda (x) (* x x))))
        (+ (square (first y)) (square(second y)))))
Eric
  • 1,093
  • 1
  • 9
  • 21
0

I think this is the smallest and most efficient way:

(define (square-sum-larger a b c)
 (+ 
  (square (max a b))
  (square (max (min a b) c))))
Elliot Gorokhovsky
  • 3,610
  • 2
  • 31
  • 56
0

Below is the solution that I came up with. I find it easier to reason about a solution when the code is decomposed into small functions.

            ; 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))
  • 1
    The question didn't ask for code to fulfill the exercise, it asked for comments on how they could improve their solution. What is good or bad about OP's code? What advantages does your way provide? Without comments this is not an answer to the question that was asked. – Chris H Aug 30 '17 at 14:01
  • @ChrisH - you are right. There are a lot of good solutions here. I'm working through SICP and found this post while looking to see what other solutions people had come up with. Since mine was a little different than others, I decided to leave it as yet another example. I will be sure to leave comments in the future. – Ethan Barrett Aug 30 '17 at 15:10
0
;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))))
andres.santana
  • 624
  • 1
  • 6
  • 13