10
\$\begingroup\$

Given the following problem (SICP Exercise 1.3):

Define a procedure that takes three numbers as arguments and returns the sum of squares of the two largest numbers.

I wrote the following (somewhat clumsy) solution in Scheme. How can I make it better?

(define (greatest-two a b c)
  (cond ((> a b) (cond ((> b c) (list a b))
                       (else (list a c))))
        ((> a c) (cond ((> c b) (list a c))
                       (else (list a b))))
        (else (list b c))))

(define (square x) (* x x))
(define (sum-of-squares a b) (+ (square a) (square b)))
(define (f a b c)
  (apply sum-of-squares (greatest-two a b c)))
\$\endgroup\$
1
  • \$\begingroup\$ I posted my solution to this question some time ago. It doesn't involve any conditionals, because I'm cheap like that. ;-) \$\endgroup\$ Mar 23, 2011 at 3:50

2 Answers 2

11
\$\begingroup\$

Scheme is a lot more functional than Common Lisp. The way you can apply that to this situation is by making more use of passing functions around (to the point that this problem is almost a one-liner). For the puzzle as written, I'd do something like

(define (big-squares a b c)
   (apply + (map (lambda (n) (* n n))
                 (take (sort (list a b c) >) 2))))

If you wanted to decompose it properly into named functions

(define (square num) (expt num 2))
(define (sum num-list) (apply + num-list))
(define (two-biggest num-list) (take (sort num-list >) 2))

(define (big-squares a b c) (sum (map square (two-biggest (list a b c)))))

If you wanted to go completely overboard, also toss in

(define (squares num-list) (map square num-list))

which would let you define big-squares as

(sum (squares (two-biggest (list a b c))))

(code above in mzscheme)

\$\endgroup\$
6
  • \$\begingroup\$ MzScheme is known these days as Racket. Just a heads-up. :-) \$\endgroup\$ Mar 23, 2011 at 6:17
  • \$\begingroup\$ @Chris - The PLT-Scheme project is known as Racket these days. I'm still running the command line version from the Debian repos, which is still mzscheme, even though the package it comes in is now called plt-scheme. :p \$\endgroup\$
    – Inaimathi
    Mar 23, 2011 at 6:28
  • 1
    \$\begingroup\$ I encourage you to grab the latest package from git://git.debian.org/collab-maint/racket.git and build yourself some brand new Racket 5.1 packages. :-D \$\endgroup\$ Mar 23, 2011 at 6:36
  • \$\begingroup\$ Wow, very elegant solution. I like this answer too :) \$\endgroup\$
    – jaresty
    Mar 23, 2011 at 6:45
  • 1
    \$\begingroup\$ @ricardo - According to this, in chez it's called list-head. \$\endgroup\$
    – Inaimathi
    Oct 21, 2013 at 14:21
5
\$\begingroup\$

So either a is the minimum of the list in which case b and c or it's not and it's one of the numbers you want to keep. The other is the max of b and c.

(define (f a b c)
  (if (or (> a b) (> a c))
      (sum-of squares a (max b c))
      (sum-of-squares b c)))

(define (square x) (* x x))
(define (sum-of-squares a b) (+ (square a) (square b)))

Of you can take the sum of the squares of all of them and subtract the square of the min.

(define (f a b c)
  (- (fold + 0 (map square (list a b c))) (square (min a b c))))
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.