Function composition — Part 1

(Part 2 here)

The best way to learn something is to write about it. So here I am, trying to learn functional programming.

My tool of choice was Racket, a former Scheme dialect that is growing to be called a language by itself.

I’m trying to bend the language to compose functions the way Factor does. So, here are my first two experiments.

What am I trying to fix?

In functional style it’s common to “pipe” data through more than one function. Let’s say I want to get the first column of a CSV file, I could do something like that:

(get-first (split-columns (open “some.csv”)))

To understand it, we have to read that back to front or keep in mind all the operations until we reach “…csv”. Get a slightly longer set of operations and things get really difficult to understand.

I want to write the same thing as:

(-> (open “some.csv”) split-columns get-first)

So I can read it from left to right: open this file, split it and get the first column. This is function composition as done by concatenative programming languages (like Factor, mentioned above).

Simple composition using macros

Let’s try a simpler thing, add one to a number and convert it to string. It’s fast and easy with macros once you figure it out.

This is a recursive macro. When Racket founds “->” as the first thing after parenthesis it tries to match against two patterns:

; if there is just one argument after "->", return it
[(-> a) a]
; if there is more arguments, apply (execute) the last one
; and call "->" again with remaining arguments as its parameter
[(-> b ... a) (a (-> b ...))]

Macros in Racket are amazingly simple once you get it, besides there is no performance penalty as they are expanded in compiling phase. However, there is one limitation: it’s not a function. That means I can’t pass it around as an argument to functions.

So, let’s try again, but before that, what are macros?

Interlude: what are macros?

Macros look like functions when you use them, but actually they modify the code before execution. Think you can modify your AST before the program runs.

This is incredibly powerful and the main use is to extend the language in ways that functions can’t.

Simple compositions using functions

It works exactly the same as the macro version, but it’s slightly different inside.

Again, it’s a recursive function. The “. ps” means “any number of arguments”.

; if I have just one argument, return it
[((list a)) a]
; if I have more arguments, call the last one (as a function)
; and then call "->" again with the remaining arguments
[((list b ... a)) (a (apply -> b))]

Conclusion

They are simple and not yet what Factor does, but it’s a (baby) step!

The second version logic seems the same for any language with functions as first class citizens (I wonder how it would be in Javascript).

Particularly in Racket there is “compose1” that is similar, but the functions are applied in reverse order. Also, in my version all functions are limited to just one argument.

These are tasks for the part 2.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store