How to print the value being returned before it's returned in Scheme?

79 Views Asked by At

I'm trying to modify this snippet from SICP:

(define (whatever x y)
    (newline)
    (display "called with ")
    (display x)
    (if (> x y)
    0            ; if x <= y, return 0 and skip the rest                
    (+ x (whatever (+ 1 x) y))))

What I want to do is add a line in "the rest" that prints out the value being returned before the value is returned. For example, now my output for (whatever 1 5) gives:

called with 1
called with 2
called with 3
called with 4
called with 5
called with 6
;Value: 15

I want it to give:

called with 1 returning 15
called with 2 returning 14
called with 3 returning 12
called with 4 returning 9
called with 5 returning 5
called with 6 returning 0
;Value: 15

Everything I try either tells me that I got the syntax wrong or says something about 'object #!unspecific' being the wrong type. I understand why I'm getting those errors (i.e. the function wants to return a number but (display (+ x (whatever (... ))) doesn't return the right kind of value).

(define...
0
(display (+ x (whatever (+ x 1) y))))

gives an error message saying object #!unspecific is the wrong type

If I change it to

(define...
0
(display (+ x (whatever (+ x 1) y))))
(+ x (whatever (+ x 1) y))))

gives an ill-formed syntax error that I can't get rid of after double and triple checking my parenthesis nesting.

If I take out the (display ... ) it works as expected.

Would anyone be willing to show me a lean way to get the output I want?

2

There are 2 best solutions below

0
On

You can't print the result until after the recursion has returned, so if you print the argument first,

(define (whatever x y)
    (display "called with ")
    (display x)
    (newline)
    (if (> x y)
        (begin
          (display "returning 0")
          (newline)
          0)
        (begin
          (let ((result (+ x (whatever (+ 1 x) y)))) 
                (display "returning ")
                (display result)
                (newline)
                result))))

the output is:

> (whatever 1 5)
called with 1
called with 2
called with 3
called with 4
called with 5
called with 6
returning 0
returning 5
returning 9
returning 12
returning 14
returning 15
15

If you want the argument and result on the same line, they end up in the other order

(define (whatever x y)
    (if (> x y)
        (begin
          (display "called with ")
          (display x)
          (display " returning 0")
          (newline)
          0)
        (begin
          (let ((result (+ x (whatever (+ 1 x) y))))
                (display "called with ")
                (display x)
                (display " returning ")
                (display result)
                (newline)
                result))))

Output

> (whatever 1 5)
called with 6 returning 0
called with 5 returning 5
called with 4 returning 9
called with 3 returning 12
called with 2 returning 14
called with 1 returning 15
15

If you want to reverse the order of that, it becomes more complicated.

0
On

The reason you are getting #!unspecific from your particular implementation is because all side effect procedures in Scheme can return any value and from R7RS it's suggested that it's a single undefined value. You could make a procedure that prints, then returns the argument:

(define (print-value value)
  (display value)
  (newline)
  value)

So in your function inplace of any value v you can do (print-value v) and it will work the same way except it will print the value of v as a side effect.