Upskill tutorial for higher order functions

Hud Wahab
5 min readJul 15, 2023

--

Day 15: Functools. Lambda. Partial. Callable.

Hi 👋 I am Hud, a postdoc for engineering data science at the AI Manufacturing Center in Laramie, Wyoming. My funding is running out (AaAaaA !), so while I am actively looking for a new job, instead of doing the 205th coding certificate to prove my worthiness — I thought I’d do design challenges and document how I spend my time upskilling so other engineers can do the same.

Nowadays, certificates are everywhere. Documenting small upskill projects that you can later show off is the best way to get recognition as a professional engineer.

This is day 15 of a 30-day design challenge. Follow along and let me know if you get stuck!

TL;DR tasks

Download the provided code for the challenge.

Task 1: Understand the code and its objectives

  • Review the provided object-oriented weather service code and its functionality.
  • Understand the goal of refactoring the code to make it functional and rely on higher-order functions.

Task 2: Convert the WeatherService class to functions

  • Extract the logic from the WeatherService class and convert it into separate functions.
  • Create a get_forecast function that takes an HttpClient, a city, and an API key as arguments, and returns the forecast object.
  • Refactor the properties that retrieve temperature, humidity, etc., into separate functions that take the forecast object as an argument and extract the relevant information.

Task 3: Transform the RequestsClient class into a higher-order function

  • Modify the RequestsClient class to be a single get function instead.
  • Convert the get function into a higher-order function by making it accept another function as an argument.

Task 4: Implement the higher-order function

  • Modify the get_forecast function to accept the HTTP getter function as an argument.
  • Replace the calls to the RequestsClient class within the get_forecast function with the provided HTTP getter function.

Task 5: Define a function with default arguments

  • Create a new function that allows getting weather forecasts without providing the HTTP getter function and API key.
  • Set default values for the HTTP getter function and the API key within this function.

Task 6: Test the functional code

  • Verify that the refactored code functions correctly by running tests or using sample data.
  • Ensure that the weather forecasts are retrieved successfully and the higher-order function is working as expected.

Task 7: Evaluate the benefits of functional code and higher-order functions

  • Consider the advantages of using functional code and higher-order functions, such as improved readability, composability, and flexibility.
  • Assess how the code has become more declarative and expressive through the use of higher-order functions.

Protocol is ok, can be better

We continue from our previous challenge where we’ve demonstrated the power of abstractions. There’s nothing really wrong with the code, I am just not quite happy and want to try shortening it. I mean, we have 4 class objects CityNotFoundError, HttpClient, RequestsClient, WeatherApi— Can we replace these classes with functions? How’d that look like? We sorta did that already here [REF], but this is an alternative — I want to emphasize and practice this bit to drill the concept deep in our brains.

Better: Higher order functions

Callable to the rescue! Again (see challenge XX). The Callable type hint is used to specify the type of a function or method that can be called with a specific set of arguments and return a specific type. In this case, HttpGet is a type hint for a function that takes a single string argument and returns a value of any type.

When get_forecast is called, the http_get parameter can be passed any function that matches the HttpGet signature, including the get function defined in the same module or any other function that takes a string argument and returns a value of any type. This allows the behavior of get_forecast to be customized by injecting a different function that retrieves the weather data from a different source or with different parameters.

Great! But how do we actually implement it?

Lambda and partial

Here’s two ways: lambda and partial.

The lambda function is an anonymous function that takes a single argument city and calls the get_forecast function with three arguments: get, API_KEY, and city. The get argument is a function that retrieves data from a URL, and API_KEY is a constant that contains the API key for the weather service. By using lambda, we can create a new function that only requires the city argument to work.

The partial function is used to create a new function that is a partial application of the get_forecast function. The first argument to partial is the function to be partially applied, followed by any arguments that should be bound to that function. In this case, we are binding the get and API_KEY arguments to get_forecast, which means that the resulting function only requires the city argument to work.

The advantage of using lambda is that it is concise and easy to read, especially for simple functions. However, it can become unwieldy for more complex functions, as it can be difficult to read and understand the code.

The advantage of using partial is that it is more flexible and can be used to create more complex functions. It can also be easier to read and understand the code, as the function signature is more explicit. However, it can be more verbose and harder to read for simple functions.

In general, lambda is a good choice for simple functions that only require a few arguments, while partial is a better choice for more complex functions that require more arguments or have more complex logic.

Did you notice that we have (almost) no traditional class objects in the whole code? Generally that makes it shorter, less boilerplate, less overhead.

Conclusion

Congratulations! You finished Day 15 from the 30-day design challenge.

If you have reached this far, you know how to:

  • Use higher order functions to replace bulky class objects

Check out the day 16 challenge!

Also, you can access the full 30-day GitHub repository here.

💡 My goal here is to help engineering data scientists upskill in design. I’d like to hear from you! Was this helpful? Anything I can improve? Connect with me on LinkedIn | Medium

--

--

Hud Wahab

🤖 Senior ML Engineer | Helping machine learning engineers design and productionize ML systems. | Let's connect: https://rb.gy/vb6au