John Smith
John Smith

Reputation: 897

Exercise 1.3 SICP why doesn't it work with 'when'?

#!/usr/bin/env racket
#lang racket/base

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

(define (procsq a b c)
  (when (and (< a b)(> c a))(+ (* b b)(* c c))) 
  (when (and (< a c)(> b a))(+ (* b b)(* c c)))
  (when (and (< b a)(> c b))(+ (* a a)(* c c)))
  (when (and (< b c)(> a b))(+ (* a a)(* c c)))
  (when (and (< c a)(> b a))(+ (* a a)(* b b)))
  (when (and (< c b)(> a c))(+ (* a a)(* b b)))) 

(displayln (procsq 1 2 3)); Why does it print #<void> ?
(displayln (procsq 3 2 1))
(displayln (procsq 3 1 2)); Why does it print #<void> ?

I coded my answer using when, why doesn't it work? The comments show with what arguments it doesn't work.

Upvotes: 0

Views: 88

Answers (2)

Will Ness
Will Ness

Reputation: 71065

Normally, a procedure returns the value of the last expression in the body, as is explained in the other answer.

In many other languages though we have the ability to return immediately from within the depths of a running procedure. Scheme too has such capability, though not through a keyword but what's known a continuation mechanism:

(define (procsq a b c)
  (call-with-current-continuation
    (lambda (return)
      (when (and (< a b)(> c a)) (return (+ (* b b)(* c c)))) 
      (when (and (< a c)(> b a)) (return (+ (* b b)(* c c))))
      (when (and (< b a)(> c b)) (return (+ (* a a)(* c c))))
      (when (and (< b c)(> a b)) (return (+ (* a a)(* c c))))
      (when (and (< c a)(> b a)) (return (+ (* a a)(* b b))))
      (when (and (< c b)(> a c)) (return (+ (* a a)(* b b)))))))

;; > (procsq 1 2 3)
;; 13

Upvotes: 1

Barmar
Barmar

Reputation: 780724

A procedure returns the value of the last expression in the body. Each when is calculating a value, but they're not being returned because it's not the last expression. It then goes to the next when. The result is the value of the last when, which will be #<void> if the condition isn't true.

Use cond when you have a series of mutually-exclusive conditions, not separate when expressions. It will return the value corresponding to the first condition that's true.

(define (procsq a b c)
  (cond ((and (< a b)(> c a)) (+ (* b b)(* c c)))
        ((and (< a c)(> b a)) (+ (* b b)(* c c)))
        ((and (< b a)(> c b)) (+ (* a a)(* c c)))
        ((and (< b c)(> a b)) (+ (* a a)(* c c)))
        ((and (< c a)(> b a)) (+ (* a a)(* b b)))
        ((and (< c b)(> a c)) (+ (* a a)(* b b)))))

Upvotes: 3

Related Questions