Reputation:
combine
must map reduce a list with the binary operator bin
but must return exc
if it finds any value that fails the predicate pred?
, and if it finds any such value it must not perform any calculation on the list.
This is a simple continuation problem.
#lang racket
(define (id x)
x)
(define (const x)
(lambda (_) x))
(define (combine pred? bin zero exc)
(call/cc
(lambda (exit)
(letrec
((f (lambda (xs)
(if (empty? xs)
zero
(if (pred? (first xs))
(exit exc)
(bin (first xs) (f (rest xs))))))))
f))))
(define product
(combine zero?
*
1
0))
(product '(1 2 3 0 4))
The code almost works, but it has a very subtle error.
It raises the following exception:
define-values: assignment disallowed;
cannot re-define a constant
constant: product
It is easy to make it work. Only a small change is needed:
(define (combine pred? bin un zero exc)
(lambda (ys)
(call/cc
(lambda (exit)
(letrec
((f (lambda (xs)
(if (empty? xs)
zero
(if (pred? (first xs))
(exit exc)
(bin (first xs) (f (rest xs))))))))
(f ys))))))
I see that the problem is that Racket the continuation of define is to define a function, but can anyone give more details? What syntatic transformations involved, for example?
Upvotes: 0
Views: 166
Reputation: 48765
Think of the order you have to have here:
(define product (combine ....))
Here you first evaluate (combine ...)
and the continuation is the rest of the program starting with storing the computed value as the name product
. Calling the continuation from withing f
jumps right back to storing product
all over again.
By calling (product '(1 2 3 0 4))
you are redefining product
since it is the continuation of the program and call/cc
captures the continuation.
In your second attempt you do a true refactoring of wrapping it in a lambda and call f with the same argument. It's just delaying when the call/cc
happens and thus what is included in the continuation. In this version the continuation is whatever comes after the (product ...)
and not the setting pf product
in (define product ...)
Upvotes: 1