On this page:
Some Notes On λ
We Are Many. We Are Lambda.
Functions on Functions
Before you go...
8.3

7 Lambda

home work!

Purpose: The purpose of this lab is to provide you with some more practice with higher-order functions, and to demonstrate how they can lead very quickly to very fun code.

Textbook References: Chapter 17: Nameless Functions

Some Notes On λ

Consider the following function, that squares and adds one to each item in a list of numbers:

(define (sqr+1 lon)
  (local [; helper : Number -> Number
          ; calculates num^2 + 1
          (define (helper num)
            (+ 1 (sqr num)))]
    (map helper lon)))

Written much more elegantly with λ:

(define (sqr+1 lon)
  (map (λ (num) (+ 1 (sqr num))) lon))

Lambdas are useful when they are terse, and used exactly once in your code. Otherwise, give them a name.

Well....almost impossible!

Notice that because lambdas don’t have a name, it’s impossible to write an anonymous function that is self-recursive. This fits our suggestion above, since you’d need to use the function twice — once recursively and once when you call it from outside the function — so you need to give it a name.

Sample Problem Design the function biggest-transformation-list that takes a list of Num -> Num functions and outputs a function that, given a number num, will return the largest result of each of the given functions applied to num.

; biggest-transformation-list : [List-of [Num -> Num]] -> [Num -> Num]
; given a list of functions l, outputs a function that given a number n,
; returns the largest of the result of applying the functions in l to n.
(define (biggest-transformation-list l)
  (lambda (n) (apply max (map (lambda (f) (f n)) l))))
(define plus8times4sqr
  (biggest-transformation-list
    (list
      (lambda (n) (+ n 8))
      (lambda (n) (* n 4))
      sqr)))
(check-expect (plus8times4sqr 2) 10)
(check-expect (plus8times4sqr 3) 12)
(check-expect (plus8times4sqr 4) 16)

We Are Many. We Are Lambda.

Goals: Practice using functions as data. Practice designing functions that produce functions. Practice using lambda to create anonymous functions. Practice with world programs.

We will design a game in which you can create many balls which move across the screen in various ways. The player can add new balls by clicking on the screen.

Starter Code: Below is the data definition for a Ball.

; A Ball is a (make-ball Nat Mode Color [Nat -> Posn])
(define-struct ball [r mode color placement])
; INTERPRETATION:
; - r is the ball's radius
; - mode is the ball's mode
; - color is the ball's color
; - placement is a function that, given the current time,
;   outputs a new coordinate for the ball to be drawn at
 
; A Mode is one of:
; - "solid"
; - "outline"
 
(define BALL-1 (make-ball 3 "solid" "red" (λ (x) (make-posn 5 x))))
(define BALL-2 (make-ball 3 "solid" "blue" (λ (x) (make-posn (+ x 2) 3))))

Starter Code: Below is the data definition for a BallWorld, as well as the main function and some graphical constants.

; A BallWorld is a (make-ball-world Nat [List-of Ball])
(define-struct ball-world [t balls])
; - where t is the amount of time that has passed
; - and balls is the balls of the world
 
(define WORLD-1 (make-ball-world 0 '()))
(define WORLD-2 (make-ball-world 10 (list BALL-1 BALL-2)))
 
 
 
; main : [List-of Ball] -> World
; Run the game with this list of initial balls
(define (main init-list)
  (big-bang (make-ball-world 0 init-list)
            [on-tick (λ (bw) (make-ball-world (add1 (ball-world-t bw))
                                              (ball-world-balls bw)))]
            [to-draw draw]
            [on-mouse place-ball]))
 
(define WIDTH 500)
(define HEIGHT 500)
(define BG (empty-scene WIDTH HEIGHT))

Exercise 1 Design the function draw-ball that given a Ball, a Posn, and an image, draws the ball at that point on that image.

Exercise 2 Design the function make-drawer that given a time will create a function that takes a Ball and an image and will draw it. Hint: Use draw-ball.

Exercise 3 Design the function draw that draws the ball world. Look at the helpers you’ve just written: especially the signature for make-drawer. What does it remind you of? How can you use that to help you?

Switch pair programming roles before continuing!

We want to be able to add new balls when the user clicks the screen. Here are some data definitions that will help us:
; A BallGenerator is a [Nat Nat Nat -> [Nat -> Posn]]
; Given the time, x-coordinate, and y-coordinate of when and where a
; ball is created, create a function that, given the current time of
; the world, will output a Posn
 
; Example:
; move-horizontally : BallGenerator
(define (move-horizontally t0 x0 y0)
  (λ (t) (make-posn (modulo (+ x0 (- t t0)) WIDTH) y0)))
(check-expect ((move-horizontally 3 5 8) 10) ; 7 seconds have passed
              (make-posn 12 8))

Exercise 4 Design the BallGenerator move-vertically.

Exercise 5 Create a constant GENERATORS, which is a [List-of BallGenerator] that will keep track of all the BallGenerators you’ve made thusfar.

Exercise 6 Design the function place-ball, that given a BallWorld, x- and y- coordinate, and MouseEvent will output a BallWorld with a Ball added to it if the person clicked (this is represented by the MouseEvent "button-down"). Feel free to use any radius, color, and mode you like.

As far as the ball’s placement: look at the data definition of a Ball, the signature of this function, and the data definition of a BallGenerator. Feel free to use any BallGenerator you like, as long as it’s used correctly!

Switch pair programming roles before continuing!

Exercise 7 Now comes the fun stuff. Design a function select-random, that given any non-empty list will select a random element from the list.

Exercise 8 Update place-ball to select a random BallGenerator from the GENERATORS you previously defined.

Exercise 9 Update place-ball to make a radius of random size. Make sure you don’t make radiuses of size 0, though, those aren’t very fun!

Exercise 10 Update place-ball to use a random make-color.

Exercise 11 Update place-ball by changing "button-down" to "drag".

Switch pair programming roles before continuing!

Functions on Functions

Goals: Practice using functions as data. Practice designing functions that produce functions. Practice using lambda to create anonymous functions.

Exercise 12 Design the function two that takes a function f : [X -> X] as input and returns another function that applies f twice in a row. That is, two returns a function which first applies f to its input, then applies f again to the output of the first application (all within one function call).

Exercise 13 Design the function three, similarly, that applies a function f three times in a row.

Exercise 14 Design the functions one and zero. Writing one is easy, but what about zero? What does it mean to apply a function to its argument zero times?

Switch pair programming roles before continuing!

The functions zero, one, two, and three look curiously similar to numbers: all they do is repeat their input some number of times. Let’s call functions like these Repeaters:

; A Repeater is a function [[X -> X] -> [X -> X]]
; That, given a one-argument function f, outputs a
; function that will repeatedly apply f some specific number of times

Exercise 15 Design a function rep->nat which consumes a Repeater as input and produces the number of times it repeats its argument. Here are some tests:
(check-expect (rep->nat zero) 0)
(check-expect (rep->nat one) 1)
(check-expect (rep->nat two) 2)
(check-expect (rep->nat three) 3)
(check-expect (rep->nat (λ (f) (λ (x) ((three f) ((two f) x))))) 5)
Hint: If you have a Repeater, all you can do is give it some inputs and see what it gives you back. So your task here is simply to devise some inputs that will force it to tell you which number it represents.

Note: You should use this function only for debugging or test cases; do not use it to implement any of the functions below.

Exercise 16 Design the function rep-add1 that increments a Repeater by 1. Remember, do not use rep->nat; you don’t need it!

Exercise 17 Design the function nat->rep that converts a Nat n to the Repeater that repeats its input n times.

Switch pair programming roles before continuing!

Exercise 18 Design the function rep+, that takes two Repeaters and produces a new Repeater that represents their sum. Remember, do not use rep->nat; you don’t need it!

Exercise 19 Design the function rep*, that takes two Repeaters and produces a new Repeater that represents their product. Remember, do not use rep->nat or rep+; you don’t need them!

Exercise 20 Design the function rep^, that takes two Repeaters and produces a new Repeater that represents the first raised to the power of the second. Remember, do not use rep->nat, rep+, or rep*; you don’t need them!

Before you go...

If you had trouble finishing any of the exercises in the lab or homework, or just feel like you’re struggling with any of the class material, please feel free to come to office hours and talk to a TA or tutor for additional assistance.