There are some ideas that have a will of their own. All the mighty strength of these wills is focused on a single goal, with a narrow-mindedness comparable only to a surgical laser. That goal is to become reality. You know this is so because these crazy stupid ideas keep happening again and again to different people.

One of these ideas is functional programming in bash.

Function composition

Remember function composition? It's defined as follows: (g ∘ f )(x) = g(f(x)). How do you even start thinking about that in bash? Well, functions in bash are named, right? So if we can reference a function by name, it shouldn't be too hard to create a new function that calls one, then calls the other with the result, and prints the output.

The problem is the "create" part. I want to be able to write something like what's possible in Haskell:

-- Given two functions
add1 = 1 +
add2 = 2 +
-- Compose in a really clean way
add3 = add1 . add2

There's no way to return a function in bash. We can return a number with return, or echo some string. That's it. A number won't cut it, so the output will need to be the name of the function. But that's not good enough, it would mean that there's no control of what gets added to the namespace. Consider: if the "return value" is a string, which is the name of the new function, then no matter what you do (assign it to another name for example), the generated name is already polluting the namespace. So it follows that the only solution is passing in the name I want for the result of the composition.

Great. So the signature (if there's even such a thing in Bash) will be something like compose(result_function, outer_function, inner_function). Let's write code for that.

compose() {
    result_fun=$1; shift
    f1=$1; shift
    f2=$1; shift
    # OK, what now?
}

One could naively write:

compose() {
    result_fun=$1; shift
    f1=$1; shift
    f2=$1; shift
    $result_fun() {
        $f1 $($f2 $*);
    }
}

But Bash throws that right back in our face, saying: $result_fun: not a valid identifier. Alright. Remember, this is a hack. What's a hack about? Breaking boundaries. What's the root of all evil? (We have several of those, now that I think about it). Anyway, one possible root of all evil is eval. It lets us build a string, and evaluate it in the current context. Can we build a string that, when evaluated, will define exactly the function we need? HELL YES!

compose() {
    result_fun=$1; shift
    f1=$1; shift
    f2=$1; shift
    eval "$result_fun() {
              $f1 \$($f2 \$*);
          }"
}

Let's see it in action!

#!/bin/bash

compose() {
    result_fun=$1; shift
    f1=$1; shift
    f2=$1; shift
    eval "$result_fun() {
              $f1 \$($f2 \$*);
          }"
}

add() {
    expr $1 + $2
}

square() {
    expr $1 \* $1
}

compose square_of_sum square add
square_of_sum 2 3

Can you guess the result? ;)

Turning it up a notch: partial application

Partial application of a function f(x,y) to a single argument creates a function g(y) such that f(x,y) = g(y) for any x and y. (Partial application can of course happen from the right, or for a specific argument; for the purposes of this post, let's just do it from the left)

If you've ever written partial application in another language, you should now see the general shape of the solution. To give you an idea, here's a solution in JavaScript, if you're into that thing:

function partial() {
  var partial_arguments = Array.prototype.slice.call(arguments),
      f = partial_arguments.shift();
  return function() {
    var rest = Array.prototype.slice.call(arguments);
    return f.apply(this, partial_arguments.concat(rest));
  };
}

function add(a, b) { return a + b; }
var add2 = partial(add, 2);
console.log(add2(3));

Or the same thing in Python. Interestingly enough, it's much cleaner, even though Python is not usually touted for its support of function programming (take a look at the built-in functools module though, it's full of awesome).

def partial(f, *args):
    def result_fun(*rest):
        return f(*(args + rest))
    return result_fun

def add(a, b):
    return a + b

add2 = partial(add, 2)

print add2(3)

So with that, let's take a look at how that same thing works in Bash:

#!/bin/bash

add() {
    expr $1 + $2
}

partial() {
    result_fun=$1; shift
    fun=$1; shift
    params=$*
    eval "$result_fun() {
        more_params=\$*;
        $fun $params \$more_params;
    }"
}

partial add2 add 2
add2 3

We can even use compose and partial together to build more and more complicated functions:

#!/bin/bash

compose() {
    result_fun=$1; shift
    f1=$1; shift
    f2=$1; shift
    eval "$result_fun() {
              $f1 \$($f2 \$*);
          }"
}

partial() {
    result_fun=$1; shift
    fun=$1; shift
    params=$*
    eval "$result_fun() {
        more_params=\$*;
        $fun $params \$more_params;
    }"
}

add() {
    expr $1 + $2
}

square() {
    expr $1 \* $1
}

partial add1 add 1
compose maybe_a_prime add1 square

maybe_a_prime 1
maybe_a_prime 2
maybe_a_prime 3
maybe_a_prime 4

So there, a tiny piece of functional programming in Bash. I hope it horrifies you as much as it does me. You can find this code along with the madness of others in this GitHub repo.

Happy hacking!