1. 54
blog.sigplan.org
1. 6

I like the article resourcing for the word “defunctionalize”.

This pattern indeed comes up all the time and I did not have a word for it.

1. 5

Interesting perspective. I find myself frequently recommending “refunctionalisation” in code reviews. E.g. when a function takes a Boolean parameter that toggles certain behaviour (in particular when it’s generally only differenrt during testing), I prefer the function to take a separate function implementing the switched behaviour as an argument instead of the Boolean.

1. 2

That’s the kind of thing I trying steer people away from in code review. It turns 2 cases to consider interested an unbounded delocalized set of cases. With a bool, my behavior is paid out in front of me. With a function parameter, it’s scattered at all call sites.

1. 1

Yes! And I can see that perspective now that this article presented it for me. I hadn’t considered that before.

I still don’t agree it’s better, though. Putting as much behaviour into a single function as possible isn’t a goal in and of itself, and being able to define the function with flat, non-branching logic makes it easier to verify that the function, although higher-order, is correctly implemented.

1. 1

You can break the function up without adding arbitrary extension points. Keep the parameter a boolean, and call different functions instead of having large branches, for example. You may still have to consider whether other callers exist when modifying the leaves, but there are fewer ways that the graph can branch.

2. 2

From the linked reference: Defunctionalization is thus a whole-program transformation where function types are replaced by an enumeration of the function abstractions in this program [1]

I’m not sure what they mean by enumerate. Suppose you have a program that begins with a few functions and creates more using function-transformations. So the total count of functions is not finite and it seems these couldn’t be finitely enumerated.

But maybe I’m not quite getting the idea.

1. 1

Perhaps there is a finite basis. If so, then we could build all relevant functions from a small set of combinators. It happens to be the case that the essential structure of Cartesian closed categories is captured by such a finite basis. Indeed, the `And` constructor from the article would be part of such a basis.

To explicitly construct the enumeration, sort all of the basis’ constructors, and assign an index to each. When the index grows greater than the number of constructors, wrap around with a modulus operation and continue on, ala ASCII. Discard any ill-typed expressions.

1. 1

Hi, OP here.

A “function abstraction” literally refers to a lambda expression (/ function decl). The term comes from the lambda calculus. So these are indeed finite.

2. 2

A few languages, including Haskell, allow type variables that abstract over type functions (second-order polymorphism)

Haskell allows that for type constructors like “Maybe” but not for type families (at least until -XUnsaturatedTypeFamilies arrives).

In fact, defunctionalization is used to mimic higher order functions at the type level: https://typesandkinds.wordpress.com/2013/04/01/defunctionalization-for-the-win/ https://free.cofree.io/2019/01/08/defunctionalization/

1. 1

When you go shopping online, you may click checkboxes to limit your search to shirts, pants, and boots, but you may not provide an arbitrary filter condition.

In my experience that type of UI is a frontend for Lucen/Solr/Elastisearch backend that has the data apropriately categorized, so the result is in fact defunctionalization on the backend to allow rapid search using text/document based storage as opposed to building arbitrarily complex sql to do the same thing.

Or maybe I read that wrong.

1. 1

OP here.

Yes, you read that right. In that case, the primordial defunctionalization would indeed by on the backend.