joe blow
joe blow

Reputation: 45

Procedure As Argument - Scheme

I am working with the following set of scheme definitions. My question is specifically about the "tail" function. What does the extra set of parentheses do that makes the function expect a procedure as an argument instead of a list, which would be the case with one set of parentheses?

(define (make-stream n f)
  (define (next m)
    (cons m (lambda () (next (f m)))))
  (next n))

(define head car)

(define (tail stream)
  ((cdr stream)))

(define (nth stream n)
  (if (= n 0) (head stream)
      (nth (tail stream) (- n 1))))

(define even (make-stream 0 (lambda (n) (+ n 2))))

Sorry if this is formatted incorrectly or is an otherwise inappropriate question, I'm trying to learn how to use this website.

Upvotes: 1

Views: 472

Answers (2)

Loïc Faure-Lacroix
Loïc Faure-Lacroix

Reputation: 13600

In scheme, an expression use the first parameter of a s-expression as the method to evaluate with the following arguments.

For example:

(+ 1 2)

It is applying + to 1 and 2.

If we complicate our example a bit, we could do something like this.

(if (> x y) + -)

Here this expression will either return the + symbol or the -. We can transform that expression a bit further... with this:

((if (> x y) + -) 1 2)

Here the if expression will either return the + or - function that will later be applied with 1 and 2.

Now back to your method!

(define (tail stream)
  ((cdr stream)))

As you can see, you have double parenthesis. It means that it will apply the function located in the cdr of stream. Just as simple as that.

If we look at your constructor for stream, we can see that your constructor is actually returning a pair with a lambda function as the second member.

The second argument of make-stream is a function that is called to generate the next number. The method f doesn't have to be passed with each next call because it's available in the scope.

Upvotes: 0

Mulan
Mulan

Reputation: 135396

My question is specifically about the "tail" function. What does the extra set of parentheses do that makes the function expect a procedure as an argument instead of a list, which would be the case with one set of parentheses?

Here's your procedure

(define (make-stream n f)
  (define (next m)
    (cons m (lambda () (next (f m)))))
  (next n))

Let's first look at what car and cdr would return

(car (make-stream 0 f) ; => 0
(cdr (make-stream 0 f) ; => (lambda () (next (f m)))

This nullary (zero-argument) procedure return by car is called a Thunk. It's commonly used to delay evaluation of a computation. In this case, it's used to prevent make-stream from infinitely recursing as soon as make-stream is supplied its two arguments.

In order to get the next value out, all we have to do is apply the thunk. Note the extra parens this time

((cdr (make-stream 0 f))) ;=> (next (f m))

That's why you see ...

(define (tail stream) ((cdr stream)))

... which will return the next cons, instead of ...

(define (tail stream) (cdr stream))

... which would return a thunk containing the next cons

Upvotes: 1

Related Questions