I'm trying to learn about catamorphisms and I've read the Wikipedia article and the first couple posts in the series of the topic for F# on the Inside F# blog.
I understand that it's a generalization of folds (i.e., mapping a structure of many values to one value, including a list of values to another list). And I gather that the fold-list and fold-tree is a canonical example.
Can this be shown to be done in C#, using LINQ's Aggregate
operator or some other higher-order method?
LINQ's Aggregate() is just for IEnumerables. Catamorphisms in general refer to the pattern of folding for an arbitrary data type. So Aggregate() is to IEnumerables what FoldTree (below) is to Trees (below); both are catamorphisms for their respective data types.
I translated some of the code in part 4 of the series into C#. The code is below. Note that the equivalent F# used three less-than characters (for generic type parameter annotations), whereas this C# code uses more than 60. This is evidence why no one writes such code in C# - there are too many type annotations. I present the code in case it helps people who know C# but not F# play with this. But the code is so dense in C#, it's very hard to make sense of.
Given the following definition for a binary tree:
One can fold trees and e.g. measure if two trees have different nodes:
In this second example, another tree is reconstructed differently:
And in this third example, folding a tree is used for drawing:
Brian's answer in the first paragraph is correct. But his code example doesn't really reflect how one would solve similar problems in a C# style. Consider a simple class
node
:With this we can create a tree in main:
We define a generic fold function in
Node
's namespace:For catamorphisms we should specify the states of data, Nodes can be null, or have children. The generic parameters determine what we do in either case. Notice the iteration strategy(in this case recursion) is hidden inside the fold function.
Now instead of writing:
We can write
Elegant, simple, type checked, maintainable, etc. Easy to use
Console.WriteLine(Node.Sum_Tree(Tree));
.It's easy to add new functionality:
F# wins in the conciseness category for
In_Order_fold
but that's to be expected when the language provides dedicated operators for constructing and using lists.The dramatic difference between C# and F# seems to be due to F#'s use of closures, to act as implicit data structures, for triggering the tail call optimization. The example in Brian's answer also takes in to account optimizations in F#, for dodging reconstructing the tree. I'm not sure C# supports the tail call optimization, and maybe
In_Order_fold
could be written better, but neither of these points are relevant when discussing how expressive C# is when dealing with these Catamorphisms.When translating code between languages, you need to understand the core idea of the technique, and then implement the idea in terms of the language's primitives.
Maybe now you'll be able to convince your C# co-workers to take folds more seriously.
I wouldn't say one value.It maps it into another structure.
Maybe an example would clarify.let's say summation over a list.
foldr (\x -> \y -> x + y) 0 [1,2,3,4,5]
Now this would reduce to 15. But actually,it can be viewed mapping to a purely syntactic structure 1 + 2 + 3 + 4 + 5 + 0. It is just that the programming language(in the above case,haskell) knows how to reduce the above syntactic structure to 15.
Basically,a catamorphism replaces one data constructor with another one.In case of above list,
[1,2,3,4,5] = 1:2:3:4:5:[] (: is the cons operator,[] is the nil element) the catamorphism above replaced : with + and [] with 0.
It can be generalized to any recursive datatypes.
Brian had great series of posts in his blog. Also Channel9 had a nice video. There is no LINQ syntactic sugar for .Aggregate() so does it matter if it has the definition of LINQ Aggregate method or not? The idea is of course the same. Folding over trees... First we need a Node... maybe Tuple could be used, but this is more clear:
Then, in C# we can make a recursive type, even this is unusual:
Now, I will quote some of Brian's code, with slight LINQ-style modifications:
...
Now, the usage is quite C#-style:
I still like F# more.
I've been doing more reading, including a Micorosft Research paper on functional programming with catamorphisms ("bananas"), and it seems that catamorphism just refers to any function that takes a list and typically breaks it down to a single value (
IEnumerable<A> => B
), like Max(), Min(), and in the general case, Aggregate(), would all be a catamorphisms for lists.I was previously under the impression that it refered to a way of creating a function that can generalize different folds, so that it can fold a tree and a list. There may actually still be such a thing, some kind of functor or arrow maybe but right now that's beyond my level of understanding.