Reputation:
I was building the map function as a matter of practice.
I came up with the following code:
#lang racket
(define (map procedure items)
(if (null? items)
empty
(cons (procedure (car items)) (map procedure (cdr items)))))
I tried this and it worked fine:
(map add1 '(1 2 3))
>> '(2 3 4)
Then I tried this and it also worked fine:
(define (scale-by-3 item)
(* 3 item))
(map scale-by-3 '(1 2 3))
>> '(3 6 9)
After that, I decided to generalize the scale procedure:
(define (scale-by-factor factor item)
(* factor item))
This scale-by-factor function works:
(scale-by-factor 3 4)
>> 12
But when I tried using it with the map:
(map (scale-by-factor 2 item) '(1 2 3))
I got the following error:
item: unbound identifier in module in: item
How do I solve this? Is there a way of solving it without lambda?
Upvotes: 0
Views: 529
Reputation: 24535
In Racket for/list
can be used to create map function:
(define (mymap proc lst)
(for/list ((item lst))
(proc item)))
(mymap add1 '(1 2 3))
; =>'(2 3 4)
Upvotes: 0
Reputation: 135207
Great solutions here. I'll offer some alternatives so you can see more ways of doing the same thing
You can define the scale-by-factor
function in curried form
(define ((scale-by-factor x) y)
(* x y))
; note it needs two applications to get the computed result now
((scale-by-factor 3) 4)
; => 12
You can define a tail-recursive map using the CPS technique I showed you on one of your other questions
(define (map f xs)
(let iter ([xs xs] [k identity])
(if (empty? xs)
(k empty)
(let ([v (f (car xs))])
(iter (cdr xs) (λ (rest) (k (cons v rest))))))))
(map (scale-by-factor 2) '(1 2 3))
; => '(2 4 6)
Upvotes: 0
Reputation: 1308
First of all, item
is indeed not bound. You haven't define it anywhere.
What you want is a partial application of scale-by-factor
. This function takes two argument and evaluates to a result. But if you partially apply it on only one argument, it will evaluate to a function that takes the other argument and evaluates to the final result.
You can achieve this using curry
in Racket, as seen here.
(define (map procedure items)
(if (null? items)
empty
(cons (procedure (car items)) (map procedure (cdr items)))))
(define (scale-by-factor factor item)
(* factor item))
(map (curry scale-by-factor 5) '(1 2 3))
It is called curry
because of this
Upvotes: 0
Reputation: 236004
It fails because item
doesn't exist at the time you call it - it's passed by map
as a parameter when traversing the list. To solve the problem, do something like this:
(map (lambda (item) (scale-by-factor 2 item))
'(1 2 3))
Or we can write a nicer alternative using curry
, which creates a lambda
that expects the missing item
parameter:
(map (curry scale-by-factor 2)
'(1 2 3))
Upvotes: 1