3

Suppose we have a Rose Tree defined, along with the corresponding fold over the datatype.

data RTree a = Node a [RTree a]

foldRTree :: (a -> [b] -> b) -> RTree a -> b
foldRTree f (Node x xs) = f x (map (foldRTree f) xs)

A recursive definition of a depth first traversal of such a structure would be:

dft :: RTree a -> [a]
dft (Node x xs) = x : concat (map dft xs)

We can express dft as a fold over Rose Trees, and in particular we can derive such a fold algebraically.

// Suppose dft = foldRTree f
// Then foldRTree f (Node x xs) = f x (map (foldRTree f) xs) (definition of foldRTree)
// But also foldRTree f (Node x xs) = dft (Node x xs) (by assumption)
//                                 = x : concat (map dft xs) (definition of dft)

// So we deduce that f x (map (foldRTree f) xs) = x : concat (map dft xs)
// Hence f x (map dft xs) = x : concat (map dft xs) (by assumption)
// So we now see that f x y = x : concat y

I suppose the reason we can do this is because foldRTree captures the general recursion structure over RTrees which brings me to my query about unfold.

We define unfold as follows:

unfold :: (a -> Bool) -> (a -> b) -> (a -> a) -> a -> [b]
unfold n h t x | n x = []
               | otherwise = h x : unfold n h t (t x)


// Or Equivalently
unfold' n h t = map h . takeWhile (not.n) . iterate t

We can express the depth first traversal as an unfold as follows:

dft (Node x xs) = x : unfold null h t xs
                         where h ((Node a xs) : ys) = a
                               t ((Node a xs) : ys) = xs ++ ys

I am struggling to find a way to develop a way of algebraically calculating the functions n h t in the same way as cons. In particular there is a ingenious step in developing the unfold which is to realise that the final argument to unfold needs to be of type [RTree a] and not just RTree a. Therefore the argument posed to dft is not passed straight to the unfold and so we reach a hurdle with regards to reasoning about these two functions.

I would be extremely grateful to anyone who could provide a mathematical way of reasoning about unfold in such a way to calculate the required functions n h, and t when expressing a recursive function (that is naturally a fold) as an unfold (perhaps using some laws linking fold and unfold?). A natural question would then be what methods we have to prove such a relation correct.

samlu1999
  • 53
  • 2
  • Hint: define the type of unfolds that have an internal state type of `s` and an output list type `[a]` as `type Unfold s a = (s -> Bool, s -> a, s -> s, s)`. These are a lot like lists; your function essentially has the type `unfold :: Unfold s a -> [a]`. Can you write `cons :: a -> Unfold s a -> Unfold ? a` for some type `?` of your choosing? `map :: (a -> b) -> Unfold s a -> Unfold ? b`? `concat :: Unfold s (Unfold s' a) -> Unfold ? a`? If you have `cons`, `map`, and `concat`, you can write down your `dft` directly with the same definition (but a different type). – Daniel Wagner May 30 '18 at 16:14

0 Answers0