Lambda in Racket Explained
Asked Answered
S

1

12

I am trying to understand lambda use in racket and I am still unclear. I get that they are unnamed (anonymous) functions but why is that good? I need to access my functions from other functions so how would I call them??? Please explain the small program below and why using lambda is better? Thank you.

; why is this better than below???
(define test
  (lambda (x)
    (lambda (y)
      (+ x y))))

(define add27
  (test 27))

; what's wrong with this???
(define (addTest x)
  (+ x 27))

> (add27 2)
29
> (addTest 2)
29
Sears answered 6/9, 2014 at 1:51 Comment(0)
U
18

In Racket (and other functional programming languages) lambdas are very useful, when you want to pass an in-line, one-shot function as a parameter without defining it first. For example, suppose that we want to square a list of numbers. We can go the long way and define a square function first, and then use map:

(define (square x)
  (* x x))

(map square '(1 2 3 4 5))
=> '(1 4 9 16 25)

… Or we can simply pass a lambda, like this:

(map (lambda (x) (* x x))
     '(1 2 3 4 5))

=> '(1 4 9 16 25)

As you can see, there exist cases where we don't need to refer to a function's name. Of course, if the procedure represented by the lambda is going to be reused in several parts, or if it's recursive then it makes sense to give it a name (so it's no longer anonymous):

(define square
  (lambda (x) (* x x)))

The above is equivalent to the first definition of square at the beginning. In fact, the first definition is just syntactic sugar to define a function, but in the end all functions are lambdas!

Now let's see your example. Here we are using a lambda in a slightly different fashion, and also exemplifies why they're useful - we're not only defining a function, but returning a function as well:

(define test
  (lambda (x)
    (lambda (y)
      (+ x y))))

Perhaps it'll be a bit clearer if we write it like this (it's equivalent, for the reasons mentioned above):

(define (test x)
  (lambda (y)
    (+ x y)))

Or even shorter - in Racket we can also use this syntax for the same purpose:

(define ((test x) y)
  (+ x y))

It's not that this is a better (or worse) way to define a function - it's a different thing! we're defining a procedure called test, that receives as parameter x and returns as a result a new anonymous function, that in turn will receive as parameter y. Now, in these lines:

(define add27
  (test 27))

… we're calling test with an x value of 27, which returns the anonymous function, and we name that function add27. Remember the lambda that received as parameter y? now that lambda has been named add27 - and this is an example of currying. Think of it: test is a function that is used for generating functions that add a fixed value x to a given parameter y, that explains why this works:

(add27 2)
=> 29

On the other hand, this function will always add 27 to its parameter with no way to change it:

(define (addTest x)
  (+ x 27))

(addTest 2)
=> 29

You see the difference? test allows us to generate new functions that add an arbitrary value, whereas addTest always adds a fixed value, 27. What if you wanted to add say, 100? using test this is simple:

(define add100 (test 100))

But addTest can't be changed, we would need to write a new function:

(define (addTest100 x)
  (+ x 100))

I hope this clarifies things, feel free to ask in the comments any additional questions about my answer.

Underslung answered 6/9, 2014 at 2:3 Comment(4)
Thank you so much for this explanation. I am still trying to understand how it all works but this is a great start. Now I just need to re-read it 500 times. =)Sears
I'm sorry but I am still unclear how this returns a function. I don't get it.Sears
@Sears a function returns the last value. For example, this returns 1 when called: (define (f) 1). And given that a lambda is also a value like any other, if we write this: (define (f) (lambda (x) x)) then we have a function that, when called, will return as a result an anonymous functionQuoits
Yep I think I got it now. Part of my confusion is the alignment of all the elements. It seems that the spacing in the functions is more confusing than it should be....for instance why can't it be written like you did in the comments instead of on multiple lines with indentation. I wrote some functions on my own with the spacing that makes sense to me and it is much clearer as to what is an argument and what is returned. I suppose one day I'll conform to the other format. Nonetheless, thank you very much Oscar!!Sears

© 2022 - 2024 — McMap. All rights reserved.