In your original code:
(define product (lambda (ol2 l1 l2)
(cond
[(and (null? l1) (null? l2)) '()]
[(null? l2) (product ol2 (rest l1) ol2)] ; here l1 gets empty and l2 becomes the same as ol2
[else (cons (list (first l1) (first l2)) (product ol2 l1 (rest l2)))])))
The base case requires both l1
and l2
to be null?
, but since l2
is replaced by ol
at the same time as l1
goes from one element to zero both will never be null
since l2
will be the original list.
Then the default case will try to use first
on the empty list. To fix this, just change the base case to terminate when just l1
is null?
:
(define product (lambda (ol2 l1 l2)
(cond
[(null? l1) '()] ; terminate when l1 is null?
[(null? l2) (product ol2 (rest l1) ol2)]
[else (cons (list (first l1) (first l2)) (product ol2 l1 (rest l2)))])))
The use of an extra variable that supposed to be the same wasn't apparent to me or other commenters. Using a named let
or local helper procedure hides implementation details that users shouldn't have to care about:
;; with named let
(define (product l1 l2)
(let product ((l1 l1) (tl2 l2))
(cond
[(null? l1) '()] ; terminate when l1 is null?
[(null? tl2) (product (rest l1) l2)]
[else (cons (list (first l1) (first tl2)) (product l1 (rest tl2)))])))
;; with local helper procedure
(define (product l1 l2)
(define (product l1 tl2)
(cond
[(null? l1) '()] ; terminate when l1 is null?
[(null? tl2) (product (rest l1) l2)]
[else (cons (list (first l1) (first tl2)) (product l1 (rest tl2)))]))
;; call the helper
(product l1 l2))
head
an alias forfirst
(orcar
)? – Alexis King(require racket/trace)
and using(trace-define (product ol2 l1 l2) ...)
, then running the function in the REPL. That will likely help make the problem more clear. – Alexis Kingol2
used for? – soegaardl1
isempty?
since whenl1
becomesempty?
l2
is reset tool2
. – Sylwester