Hands On: Higher Order Functions

In this exercise we are going to get some hands on practice using higher order functions. We are going to have a form simulating a ticket booking UI. The user can enter the number of tickets to book and submit the form to book the tickets.

This is what the UI looks like

Problem Statement

There are three pieces of code that we will deal with in this exercise:

  • A Form object that accepts the number of tickets to book from the user
  • A book_tickets function that simulates a call to the backend with the number of tickets to book. The number of tickets to book will come from the Form class
  • A get_token function that creates an authentication token which needs to be passed to book_tickets in order to make the backend call

We need to integrate these three bits of code together. Writing that integration is the goal of this exercise.

The Form class

This class accepts a submit handler. When the user submits the form, the UI will call submit which in turn will execute the submit handler with the number of tickets booked by the user.

class Form:
    def __init__(self):
        self.handler = lambda x: None

    def on_submit(self, handler):
        self.handler = handler

    def submit(self, num_tickets):
        self.handler(num_tickets)

get_token

This function just returns a token. The token should be passed as the first parameter of book_tickets

def get_token():
    return "A123"

book_tickets

This function takes the token (from get_token above) and the number of tickets to book (from the form). If the token is valid, it simulates a call to the backend (it just prints a message to indicate this).

def book_tickets(token, num_tickets):
    if token != "A123":
        print("Invalid token")
        return
    print(f"Booked {num_tickets} tickets")

What we need to do

  1. Part 1: Implement the main function, which takes the form as input. Pass in an appropriate function to form.on_submit such that when the form is submitted, it calls book_tickets with the right parameters. We cannot modify any of the existing code for form, get_token or book_tickets. We can only change main
  2. Part 2: Write the code in such a way that if the user double-clicks the Book Tickets button, it still makes only a single call to the backend

Code

def main(form):
    # write code here to connect the form,
    # get_token and book_tickets
    form.on_submit(???)

Output

Initialising code editor. Please wait.
Error: {{error}}
Code editor ready. Write your code in the editor and click the Run button to view the output here
(Click this button multiple times)
Backend Called: {{ output }}
Oops, we should call the backend only once even when the button is clicked multiple times
from js import editor, render_output, render_error, change_states class Form: def __init__(self): self.handler = lambda x: None def on_submit(self, handler): self.handler = handler def submit(self, num_tickets): self.handler(num_tickets) def get_token(): return "A123" def book_tickets(token, num_tickets): if token != "A123": return render_error("Invalid token") render_output(f"Booked {num_tickets} tickets") f = Form() def run(*args, **kwargs): code = editor.getValue() try: exec(code, globals()) main(f) change_states({"ready": True, "error": "", "outputs": []}) except Exception as e: render_error(str(e)) def do_booking(*args, **kwargs): num_tickets = Element("input").element.value try: f.submit(int(num_tickets)) except Exception as e: render_error(str(e))

Solution Hints

Feel free to expand any of the hints below to guide you while implementing this exercise.

Guided Hint 1

You need to configure a handler function to the form by calling on_submit such that book_tickets is executed when the form is submitted

Guided Hint 2

form.submit will call the handler function with a single parameter (num_tickets) but book_tickets requires two parameters

Guided Hint 3

Maybe we can partially apply the first parameter to book_tickets before setting it as the event handler. When form.submit is called it will pass in the second parameter and book_tickets will get executed

Solution Part 1

Use form.on_submit(partial(book_tickets, get_token())) inside the main function. (Don't forget to do from functools import partial on top). Then proceed to part 2 – even if the book tickets button is clicked multiple times it should still call the backend once

Guided Hint 4

Click the button multiple times. Notice that it calls the backed multiple times. How can we make book_tickets get executed only once? 

Guided Hint 5

Remember we wrote a higher order function once in the article on impure functions? Maybe we can use that?

Solution Part 2

Copy and paste the implementation of the once function from the impure functions article. Then change on_submit to wrap the function with once before setting it as the handler: form.on_submit(once(partial(book_tickets, get_token())))