0

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?

  • Answers will be different for Racket and Lisp. A Lisp programmer might write an [anaphoric macro](https://en.wikipedia.org/wiki/Anaphoric_macro). – molbdnilo Oct 19 '16 at 08:56

4 Answers4

1

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))
Óscar López
  • 232,561
  • 37
  • 312
  • 386
0

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

Steinway Wu
  • 1,288
  • 1
  • 12
  • 18
0

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)
Community
  • 1
  • 1
Mulan
  • 129,518
  • 31
  • 228
  • 259
0

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)
rnso
  • 23,686
  • 25
  • 112
  • 234