user4206400
user4206400

Reputation:

Building map with Racket

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

Answers (4)

rnso
rnso

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

Mulan
Mulan

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

Steinway Wu
Steinway Wu

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

Óscar López
Óscar López

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

Related Questions