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. >
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:
public class Node
{
public TLeft Left { get; private set; }
public TRight Right { get; private set; }
public TData Data { get; private set; }
public Node(TData x, TLeft l, TRight r){ Data = x; Left = l; Right = r; }
}
Then, in C# we can make a recursive type, even this is unusual:
public class Tree : Node* data: */ T, /* left: */ Tree, /* right: */ Tree>
{
// Normal node:
public Tree(T data, Tree left, Tree right): base(data, left, right){}
// No children:
public Tree(T data) : base(data, null, null) { }
}
Now, I will quote some of Brian's code, with slight LINQ-style modifications:
...
public static class TreeExtensions
{
private static R Loop(Func, R> nodeF, Func, R> leafV, Tree t, Func cont)
{
if (t == null) return cont(leafV(t));
return Loop(nodeF, leafV, t.Left, lacc =>
Loop(nodeF, leafV, t.Right, racc =>
cont(nodeF(t.Data, lacc, racc, t))));
}
public static R XAggregateTree(this Tree tree, Func, R> nodeF, Func, R> leafV)
{
return Loop(nodeF, leafV, tree, x => x);
}
public static R Aggregate(this Tree tree, Func nodeF, R leafV)
{
return tree.XAggregateTree((x, l, r, _) => nodeF(x, l, r), _ => leafV);
}
}
Now, the usage is quite C#-style:
[TestMethod] // or Console Application:
static void Main(string[] args)
{
// This is our tree:
// 4
// 2 6
// 1 3 5 7
var tree7 = new Tree(4, new Tree(2, new Tree(1), new Tree(3)),
new Tree(6, new Tree(5), new Tree(7)));
var sumTree = tree7.Aggregate((x, l, r) => x + l + r, 0);
Console.WriteLine(sumTree); // 28
Console.ReadLine();
var inOrder = tree7.Aggregate((x, l, r) =>
{
var tmp = new List(l) {x};
tmp.AddRange(r);
return tmp;
}, new List());
inOrder.ForEach(Console.WriteLine); // 1 2 3 4 5 6 7
Console.ReadLine();
var heightTree = tree7.Aggregate((_, l, r) => 1 + (l>r?l:r), 0);
Console.WriteLine(heightTree); // 3
Console.ReadLine();
}
I still like F# more.