I am taking a class in Haskell, and we need to define the fold operation for a tree defined by:
data Tree a = Lf a | Br (Tree a) (Tree a)
I can not seem to find any information on the "tfold" operation or really what it supposed to do. Any help would be greatly appreciated.
Imagine you define that a tree should be shown in the following manner,
<1 # <<2#3> # <4#5>>>
Folding such a tree means replacing each branch node with an actual supplied operation to be performed on the results of fold recursively performed on the data type's constituents (here, the node's two child nodes, which are themselves, each, a tree), for example with +
, producing
(1 + ((2+3) + (4+5)))
So, for leaves you should just take the values inside them, and for branches, recursively apply the fold for each of the two child nodes, and combine the two results with the supplied function, the one with which the tree is folded. (edit:) When "taking" values from leaves, you could additionally transform them, applying a unary function. So in general, your folding will need two user-provided functions, one for leaves, Lf
, and another one for combining the results of recursively folding the tree-like constituents (i.e. branches) of the branching nodes, Br
.
Your tree data type could have been defined differently, e.g. with possibly empty leaves, and with internal nodes also carrying the values. Then you'd have to provide a default value to be used instead of the empty leaf nodes, and a three-way combination operation. Still you'd have the fold defined by two functions corresponding to the two cases of the data type definition.
Another distinction to realize here is, what you fold, and how you fold it. I.e. you could fold your tree in a linear fashion, (1+(2+(3+(4+5)))) == ((1+) . (2+) . (3+) . (4+) . (5+)) 0
, or you could fold a linear list in a tree-like fashion, ((1+2)+((3+4)+5)) == (((1+2)+(3+4))+5)
. It is all about how you parenthesize the resulting "expression". Of course in the classic take on folding the expression's structure follows that of the data structure being folded; but variations do exist. Note also, that the combining operation might not be strict, and the "result" type it consumes/produces might express compound (lists and such), as well as atomic (numbers and such), values.
(update 2019-01-26) This re-parenthesization is possible if the combining operation is associative, like +
: (a1+a2)+a3 == a1+(a2+a3)
. A data type together with such associative operation and a "zero" element (a+0 == 0+a == a
) is known as "Monoid", and the notion of folding "into" a Monoid is captured by the Foldable
type class.
I always think of folds as a way of systematically replacing constructors by other functions. So, for instance, if you have a do-it-yourself List
type (defined as data List a = Nil | Cons a (List a)
), the corresponding fold can be written as:
listfold nil cons Nil = nil
listfold nil cons (Cons a b) = cons a (listfold nil cons b)
or, maybe more concisely, as:
listfold nil cons = go where
go Nil = nil
go (Cons a b) = cons a (go b)
The type of listfold
is b -> (a -> b -> b) -> List a -> b
. That is to say, it takes two 'replacement constructors'; one telling how a Nil
value should be transformed into a b
, another replacement constructor for the Cons
constructor, telling how the first value of the Cons
constructor (of type a
) should be combined with a value of type b
(why b
? because the fold has already been applied recursively!) to yield a new b
, and finally a List a
to apply the whole she-bang to - with a result of b
.
In your case, the type of tfold
should be (a -> b) -> (b -> b -> b) -> Tree a -> b
by analogous reasoning; hopefully you'll be able to take it from there!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With