# Introduction to Functional Programming with Anonymous Functions, Part 2

Tucker McClure is an Application Engineer with The MathWorks. He spends his time helping our customers accelerate their work with the right tools and problem-solving techniques. Today, he'll be discussing how "functional programming" can help create brief and powerful MATLAB code.

### Contents

#### Recap

For Part 1, click here.

Last time, we said that functional programming was marked by storing functions as variables (function handles) and working with functions that act on other functions. We put these ideas together to implement our own version of a `map` function for handling multiple inputs and outputs from multiple functions simultaneously, and we created `iif`, an "inline if", to allow the use of conditional statements inside of anonymous functions. So how might we work with recursive functions -- functions of themselves? We'll see how a functional programming style allows us to implement recursive functionality inside anonymous functions, and this will pave the way for the final part, in which we'll implement loops, without ever using `for` or `while` (which we can't use in anonymous functions).

Before we get started, let's implement `iif` again; we're going to need it frequently.

```
iif = @(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}();
```

#### Anonymous Function Recursion

Recall that a recursive function is a function that calls itself. It therefore needs some way to refer to itself. When we write an anonymous function, it isn't "named" (hence, "anonymous"), so it can't call itself by name. How can we get around this?

Let's start with a Fibonacci sequence example. Recall that the nth number of the Fibonacci sequence is the sum of the previous two numbers, starting with 1 and 1, yielding 1, 1, 2, 3, 5, 8, 13, 21, etc. This is easy to implement recursively.

fib = @(n) iif(n <= 2, 1, ... % First two numbers true, @() fib(n-1) + fib(n-2)); % All later numbers

But hey, that can't work! We haven't defined `fib` yet, so how could this anonymous function call it? In fact, the anonymous function will never "know" we're referring to it as `fib`, so this won't work at all. Therefore, instead of trying to call `fib` directly, let's provide another input: the handle of a function to call, `f`.

fib = @(f, n) iif(n <= 2, 1, ... % First two numbers true, @() f(f, n-1) + f(f, n-2)); % All later numbers

Getting closer. Now, if we pass `fib` *to* `fib` along with the number we want, it will call `fib`, passing in `fib` as the first argument, recursively until we get our answer.

fib(fib, 6)

ans = 8

Ok, that's right. The sixth number of the sequence is 8. On the other hand, the syntax we've created is terrible. We have to provide the function to itself? I'd rather not. Instead, let's just write a new function that hands `fib` to `fib` along with the input `n`.

fib2 = @(n) fib(fib, n); fib2(4) fib2(5) fib2(6)

ans = 3 ans = 5 ans = 8

That's a lot closer to what we want, but there's one more step. Let's write a function called `recur` to hand a function handle to itself, along with any other arguments. This makes recursion less cumbersome.

recur = @(f, varargin) f(f, varargin{:});

That was simple, so now let's re-write `fib`. The first argument to `recur` is the function, which we'll define inline. The second is `n`. That's all there is to it. It now reads as "Recursively call a function that, if `k <= 2`, returns one, and otherwise returns the recursive function of `k-1` plus that of `k-2`, starting with the user's input `n`." (If it doesn't read quite this clearly at first, that's ok. It takes some getting used to. Comment liberally if necessary!)

fib = @(n) recur(@(f, k) iif(k <= 2, 1, ... true, @() f(f, k-1) + f(f, k-2)), ... n);

And we can find the first ten numbers of the sequence via arrayfun.

arrayfun(fib, 1:10)

ans = 1 1 2 3 5 8 13 21 34 55

Factorial (f(n) = 1 * 2 * 3 * ... n) is another easy operation to represent recursively.

```
factorial = @(n) recur(@(f, k) iif(k == 0, 1, ...
true, @() k * f(f, k-1)), n);
arrayfun(factorial, 1:7)
```

ans = Columns 1 through 6 1 2 6 24 120 720 Column 7 5040

A number to an integer power has a nearly identical form. Here's `4.^(0:5)`.

```
pow = @(x, n) recur(@(f, k) iif(k == 0, 1, ...
true, @() x * f(f, k-1)), n);
arrayfun(@(n) pow(4, n), 0:5)
```

ans = 1 4 16 64 256 1024

That was a big step for anonymous functions, using both recursion and an inline conditional together with ease. Like `map` and `iif`, `recur`, looks strange at first, but once it's been seen, it's hard to forget how it works (just make one of the inputs a function handle and pass it to itself). And recursion doesn't have to stop at interesting mathematical sequences of numbers. For instance, in the next part, we'll use this to implement loops in, but first, we'll need a some helper functions and a good way to execute multiple statements in an anonymous function.

#### Helpers

These little functions are useful in many circumstances, and we're going to need `curly` frequently.

paren = @(x, varargin) x(varargin{:}); curly = @(x, varargin) x{varargin{:}};

They allow us to write `x(3, 4)` as `paren(x, 3, 4)` and similarly for curly braces. That is, now we can think of parentheses and curly braces as functions! At first this might not seem useful. However, imagine writing a function to return the width and height of the screen. The data we need is available from this call:

```
get(0, 'ScreenSize')
```

ans = 1 1 1920 1200

However, we don't need those preceeding ones. We could save the output to a variable, say `x`, and then access x(3:4), but if we need this in an anonymous function, we can't save to a variable. How do we access just elements 3 and 4? There are numerous ways, but `paren` and `curly` are similar to constructs found in other languages and are easy to use, so we'll use those here.

Now we can write our `screen_size` function to return just the data we want.

```
screen_size = @() paren(get(0, 'ScreenSize'), 3:4);
screen_size()
```

ans = 1920 1200

While on the subject, note that we can actually use any number of indices or even ':'.

magic(3) paren(magic(3), 1:2, 2:3) paren(magic(3), 1:2, :)

ans = 8 1 6 3 5 7 4 9 2 ans = 1 6 5 7 ans = 8 1 6 3 5 7

We do the same with the curly braces. Here, the regular expression pattern will match both 'rain' and 'Spain', but we'll only select the second match.

spain = curly(regexp('The rain in Spain....', '\s(\S+ain)', 'tokens'), 2)

spain = 'Spain'

(Click for Regexp help.)

It also works with ':' (note that the single quotes are required).

[a, b] = curly({'the_letter_a', 'the_letter_b'}, ':')

a = the_letter_a b = the_letter_b

#### Executing Multiple Statements

With `curly` in place, let's examine something a little different. Consider the following:

do_three_things = @() {fprintf('This is the first thing.\n'), ... fprintf('This is the second thing.\n'), ... max(eig(magic(3)))}; do_three_things()

This is the first thing. This is the second thing. ans = [25] [26] [15]

We've executed three statements on a single line. All of the outputs are stored in the cell array, so we have three elements in the cell array. The first two outputs are actually garbage as far as we're concerned (they're just the outputs from `fprintf`, which is the number of bytes written, which we don't care about at all). The last output is from `max(eig(magic(3)))`; That is, the biggest eigenvalue of `magic(3)` is exactly 15. Let's say we just wanted that final value, the eigenvalue. It's the third element of the cell array, so we can grab it with `curly`.

do_three_things = @() curly({fprintf('This is the first thing.\n'), ... fprintf('This is the second thing.\n'), ... max(eig(magic(3)))}, 3); do_three_things()

This is the first thing. This is the second thing. ans = 15

For a more complex example, let's say we want to write a function to:

- Create a small figure in the middle of the screen
- Plot some random points
- Return the handles of the figure and the plot

Then by storing all of the outputs in a cell array and using `curly` to access the outputs we care about, we can make a multi-line function with multiple outputs, all in a simple anonymous function.

dots = @() curly({... figure('Position', [0.5*screen_size() - [100 50], 200, 100], ... 'MenuBar', 'none'), ... % Position the figure plot(randn(1, 100), randn(1, 100), '.')}, ... % Plot random points ':'); % Return everything [h_figure, h_dots] = dots()

h_figure = 3 h_dots = 187

(As a quick aside, note that if a statement doesn't return anything, we can't put it in a cell array, and so we can't use it this way. There are ways around this, discussed here.)

#### To Be Continued

Today, we've come a long way, from a simple condition through recursion and executing multiple statements. Here's a roundup of the functions so far.

map = @(val, fcns) cellfun(@(f) f(val{:}), fcns); mapc = @(val, fcns) cellfun(@(f) f(val{:}), fcns, 'UniformOutput', 0); iif = @(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}(); recur = @(f, varargin) f(f, varargin{:}); paren = @(x, varargin) x(varargin{:}); curly = @(x, varargin) x{varargin{:}};

These can also be found here, implemented as regular MATLAB functions that can be kept on the path.

Next time, we'll look at loops. Until then, have you worked with functions such as `paren` or `curly`? How else are people implementing these or similar operations? Let us know here.

## 댓글

댓글을 남기려면 링크 를 클릭하여 MathWorks 계정에 로그인하거나 계정을 새로 만드십시오.