At the bottom of the article "How do you become better at programming?" is a mention of the robot kata. In this article, we will look at how to solve it using a functional programming approach.

## The Robot Kata

Here is the problem statement:

• Imagine a robot that is at position (0, 0) and facing North.
• It can take 3 commands: Move forward, turn left or turn right.
• Turning left or right changes the orientation of the robot by 90 degrees without changing the position. For example, turn left will make the robot remain at (0, 0) but it will face West now
• Moving forward will move the robot 1 step in the direction faced, so if it is at (0, 0) and facing West, after moving forwards it will be at (-1, 0) and still facing West

Given a sequence of commands (eg: FLFFLFFFRRRF) then calculate the final position and orientation of the robot.

In this article, we will see how to solve this kata using a functional programming style.

## Storing the data

First, we need to decide how we want to represent the data. The robot has 3 state variables:

• The current x coordinate
• The current y coordinate
• The direction it is facing: E, S, W, N

We have multiple options to represent this data. We could create a `class`, use a `dataclass`, use a `namedtuple`, or just a regular `tuple`.

Since this is a simple application, we will just go with a regular `tuple`

To make the data clearer, let us use Python's type hinting feature to create some data types.

• `Direction` can be one of `North`, `South`, `East` or `West`
• `Position` is a tuple containing the `x` and `y` coordinates
• The overall `RobotState` is a tuple containing the `Position` and `Direction`
``````from typing import Tuple, Literal

Direction = Literal["North", "South", "East", "West"]
Position = Tuple[int, int]
RobotState = Tuple[Position, Direction]``````

(If you are using Python 3.10+ then you can replace `Tuple` with `tuple`.)

Now, we write a function to create the tuple. Given the `position` and `direction` it will just make a tuple out of it

``````def make_robot(position: Position, direction: Direction) -> RobotState:
return (position, direction)
``````

## Moving the robot

Now that we have a way to represent the robot state, we can implement the three functions that we need. We will use structural pattern matching feature here.

``````def move(robot: RobotState) -> RobotState:
(x, y), dir = robot
match dir:
case "North":
return make_robot((x, y + 1), dir)
case "South":
return make_robot((x, y - 1), dir)
case "East":
return make_robot((x + 1, y), dir)
case "West":
return make_robot((x - 1, y), dir)

def left(robot: RobotState) -> RobotState:
pos, dir = robot
match dir:
case "North":
return make_robot(pos, "West")
case "South":
return make_robot(pos, "East")
case "East":
return make_robot(pos, "North")
case "West":
return make_robot(pos, "South")

def right(robot: RobotState) -> RobotState:
pos, dir = robot
match dir:
case "North":
return make_robot(pos, "East")
case "South":
return make_robot(pos, "West")
case "East":
return make_robot(pos, "South")
case "West":
return make_robot(pos, "North")``````

Each of these functions take in one `RobotState` as input and return a new `RobotState` as the output.

One interesting thing to note here is how we use the iterable unpacking feature with the tuple

``(x, y), dir = robot``

If you have never used type hints, iterable unpacking or structural pattern matching, then you should definitely take a look at them. They can really make your python code much easier to read and maintain. We will be doing articles on all those topics shortly.

## Composing the functions

Once we have the basic functions written, we need to be able to compose them together so that we can give a sequence of commands.

Here is a compose function like the one we wrote previously, but can take any number of functions for composition

``````def compose(*funcs):
first, second, *rest = funcs
if rest:
second = compose(second, *rest)
return lambda *args, **kwargs: second(first(*args, **kwargs))``````

With that we can now write a function to execute a sequence of commands

``````def run_commands(commands: str):
command_mapping = {"L": left, "R": right, "F": move}
functions = [command_mapping[command] for command in commands]
return compose(*functions)``````

and we can run a sequence

``````sequence = run_commands("FLFFLFFFRRRF")
start = make_robot((0, 0), "North")
end = sequence(start)
print(end) # Output is ((-1, -2), "East")``````

## Summary

In this article, we saw how to implement the robot kata using a functional programming style in python. We create the basic functions `move`, `left` and `right` and then we can use `compose` to combine them in any order and calculate any sequence of movement.

In order for compose to work, the output of one function must match the input of the next function. What happens if this is not the case? That is the topic of the next article.