# Currying in CircuitPython

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/073/595/medium800/circuitpython_1024px-Chicken_makhani.jpg?1553395967 Butter Chicken by wikipedia user Themightyquill CC BY-SA 2.0)

If you happen to have at least dabbled with the programming language Haskell, or one similar, you may be familiar with _currying_, aka partially applied functions. Partial function application is an important mechanic in functional programming. Functional programming is a hot topic these days: many of its core features are showing up in other languages, including Python.

A partially applied function is a function that has been given some arguments, but not all. In Haskell you might see a function declaration such as:

`add    :: Integer -> Integer -> Integeradd x y =  x + y`

Our traditional understanding of functions would lead us to believe that this declares a function `add`&nbsp;which takes two integer arguments and returns an integer result which is the sum of the arguments.&nbsp; We would be wrong. This, in fact, declares a function that takes an integer and returns another function that takes an integer and returns one. I.e.

`add:: Integer -> (Integer -> Integer)`

When `add` is called, it returns a function that has been partially applied (to the first argument). The resulting function can then be applied to the second (and final) argument to generate a result.

Normally, we'd call `add` with both parameters:

`Prelude> add 2 35`

but because of being able to partially apply functions, we can call `add` with one parameter and get a function back. For example:

`Prelude> inc = add 1`  
`Prelude> :t inc`  
`inc :: Num a => a -> a`

`inc` is a function that takes an number and returns the number plus one. (`:t` tells you the type of its argument) That function is essentially:

`inc y = 1 + y`

So now we can use `inc`:

`Prelude> inc 2`  
`3`

This is called currying in honor of Haskell Curry, after whom the Haskell language is also named.

This is just how things work in Haskell, but Python gives us the tools we need to do it there as well.

# Currying in CircuitPython

## CircuitPython

![](https://cdn-learn.adafruit.com/assets/assets/000/073/579/medium800/circuitpython_blinka-small.png?1553361218)

We'll be using CircuitPython for this guide. Are you new to using CircuitPython? No worries,&nbsp;[there is a full getting started guide here](https://learn.adafruit.com/welcome-to-circuitpython).

Adafruit suggests using the Mu editor to edit your code and have an interactive REPL in CircuitPython.&nbsp;[You can learn about Mu and its installation in this tutorial](https://learn.adafruit.com/welcome-to-circuitpython/installing-mu-editor).

Install the&nbsp;[latest release of CircuitPython, version 4](https://github.com/adafruit/circuitpython/releases)&nbsp;(or higher) for your particular CircuitPython-compatible board. Follow the instructions&nbsp;[here](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython)&nbsp;using the appropriate CircuitPython UF2 file.

# Currying in CircuitPython

## Simple Partial Application

![](https://cdn-learn.adafruit.com/assets/assets/000/073/602/medium800/circuitpython_Untitled.png?1553523087 Rajma Chawal photo by wikipedia user Barthateslisa CC BY_SA 4.0)

We can make simple partials using the Python&nbsp;`lambda`. Here's a Python version of the `add` function we looked at in Haskell:

```auto
def add(x, y):
    return x + y
```

Python doesn't support currying as part of the language, so we can't just do:

`add(1)`

If we try, an exception is raised:

`>>> inc = add(1)`  
`Traceback (most recent call last):`  
`File "", line 1, in `  
`TypeError: function takes 2 positional arguments but 1 were given`

What we can do is use a lambda as described in [this guide](https://learn.adafruit.com/circuitpython-101-functions):

`>>> inc = lambda x: add(1, x)`  
`>>> inc(2)`  
`3`

We can go a bit further with this approach and define a function that does this for us, taking the first argument on which to partially apply add:

```auto
def make_adder(x):
    return lambda y: add(x, y)
```

Now we can use `make_adder` to, in essence, partially apply `add` to an argument:

`>>> inc = make_adder(1)`  
`>>> inc(2)`  
`3`

Since `make_adder` is general, we can use it to create any "add a constant" functions. E.g.

`>>> add10 = make_adder(10)`  
`>>> add10(5)`  
`15`

This approach can be useful, but requires a specialized partial application function for each case. Python provides the capability to come up with a more general solution.

# Currying in CircuitPython

## More Complex Partial Application

![](https://cdn-learn.adafruit.com/assets/assets/000/073/599/medium800/circuitpython_1024px-Pointed_Gourd_Curry_-_Kolkata_2011-09-20_5428.jpg?1553397499 Bengali gourd curry by wikipedia user Kolkata CC BY 3.0)

When thinking about a more general way to partially apply a functions, it would seem to be nice to partially apply to any number of argument, and to handle keyword arguments. As an exercise, we'll build it up step by step.

Let's start by considering the general form of the partial application function. We'll need to provide the function to be partially applied and the arguments to which it should be partially applied. We'll start with positional arguments.

`def partial(func, *args):`  
`    pass`

The next step is to create the function to capture the partial application:

`def partial(func, *args):`  
`    def newfunc(*fargs):        pass``    return newfunc`

`newfunc`&nbsp;has to take the arguments that are passed to it and combine them with those supplied earlier (to the `partial` function), then call the original function with the resulting arguments:

` def newfunc(*fargs):`  
`    return func(*(args + fargs))`

It can simply concatenate the positional arguments (keeping the order correct) since they are in lists.

The&nbsp;`partial` function is now:

```auto
def partial(func, *args):
    def newfunc(*fargs):
        return func(*(args + fargs))
    return newfunc
```

Now we can say:

`>>> inc = partial(add, 1)`  
`>>> inc(2)`  
`3`

## With Keywords

Now we can add keyword arguments. We can make a simple function to build strings:

`>>> def wrap(s, prefix='', suffix=''):`  
`... return prefix + s + suffix`  
`...`  
`>>> wrap('hello')`  
`'hello'`  
`>>> wrap('hello', suffix=' world')`  
`'hello world'`  
`>>> wrap('hello', suffix=' world', prefix='>>> ')`  
`'>>> hello world'`

We can use partial application to take `wrap` and make a greeter function:

`>>> greet = partial(wrap, prefix='Hello, ')`  
`>>> greet('Dave')`  
`'Hello, Dave'`

`>>> greet('Phil', suffix='!')`  
`'Hello, Phil!'`

To expand `partial` to extend partial application to keyword arguments, we need to add them to the functions, and combine them for the fully applied call. Since they are passed in dictionaries, we can't simply concatenate the way we did with the positional arguments; we need to merge the dictionaries using `update`. Our new partial function is now:

```auto
def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    return newfunc
```

# Currying in CircuitPython

## Wrap up

![](https://cdn-learn.adafruit.com/assets/assets/000/073/596/medium800/circuitpython_Paper_Masala_Dosa.jpg?1553396361 Dosa by wikipedia user SteveR CC BY 2.0)

Functional Programming has been around for quite a while and concepts from it are making their way into more mainstream languages. Partial function application is one example that can be very handy to have in your toolbox.

A big advantage of using partial application is allowing us to take general functions and specialize them at runtime.

Instead of writing special purpose functions, we can reuse general functions. This allows us to have less code, especially if the functions are complicated. It helps our code to be simpler, since using situation specific functions (with fewer arguments and more specific names) makes our code less cluttered and more readable.

Finally, reusing general purpose functions and specializing them by partial application doesn't add new logic which could have bugs.


## Related Guides

- [Adafruit Metro M4 Express featuring ATSAMD51](https://learn.adafruit.com/adafruit-metro-m4-express-featuring-atsamd51.md)
- [Adafruit Feather M4 Express](https://learn.adafruit.com/adafruit-feather-m4-express-atsamd51.md)
- [Introducing the Adafruit Grand Central M4 Express](https://learn.adafruit.com/adafruit-grand-central.md)
- [eInk / ePaper Weather Station](https://learn.adafruit.com/epaper-weather-station.md)
- [Circuit Playground Express Rocket Lamp](https://learn.adafruit.com/cpx-rocket-lamp.md)
- [CLUE Text Telephone Transmitter](https://learn.adafruit.com/clue-teletype-transmitter.md)
- [Star Trek Soundboard with NeoTrellis](https://learn.adafruit.com/star-trek-sound-board-with-neotrellism4.md)
- [Feather + Raspberry Pi Weather Monitoring Network with LoRa or LoRaWAN](https://learn.adafruit.com/multi-device-lora-temperature-network.md)
- [UART Communication Between Two CircuitPython Boards](https://learn.adafruit.com/uart-communication-between-two-circuitpython-boards.md)
- [ePaper Maze Maker](https://learn.adafruit.com/epaper-maze-maker.md)
- [PyLeap CLUE Sensor Plotter](https://learn.adafruit.com/pyleap-clue-sensor-plotter.md)
- [Using the Android CircuitPython Editor](https://learn.adafruit.com/using-the-android-circuitpython-editor.md)
- [Using the Bluefruit Dashboard with Web Bluetooth in Chrome](https://learn.adafruit.com/bluefruit-dashboard-web-bluetooth-chrome.md)
- [MLX90640 Thermal Camera with Image Recording](https://learn.adafruit.com/mlx90640-thermal-image-recording.md)
- [PyLeap BLE Controlled NeoPixels with CLUE](https://learn.adafruit.com/pyleap-ble-controlled-neopixels-with-clue.md)
- [ePaper Calendar Featuring Metro M4 Express Airlift and Tri-Color ePaper Shield](https://learn.adafruit.com/epaper-calendar-featuring-metro-m4-express-airlift-and-epaper-shield.md)
- [Paper Airplane Launcher](https://learn.adafruit.com/paper-airplane-launcher-with-crickit.md)
- [Make it Move with Crickit](https://learn.adafruit.com/make-it-move-with-crickit.md)
