I am currently learning folds in the sense of structural recursion/catamorphisms. I implemented power and factorial using a fold for natural numbers. Please note that I barely know Haskell, so the code is probably awkward:
foldNat zero succ = go
where
go n = if (n <= 0) then zero else succ (go (n - 1))
pow n = foldNat 1 (n*)
fact n = foldNat 1 (n*) n
Next I wanted to adapt the fibonacci sequence:
fib n = go n (0,1)
where
go !n (!a, !b) | n==0 = a
| otherwise = go (n-1) (b, a+b)
With fib I have a pair as second argument whose fields are swapped at each recursive call. I am stuck at this point, because I don't understand the mechanics of the conversion process.
[EDIT]
As noted in the comments my fact function is wrong. Here is a new implementation based on a paramorphism (hopefully):
paraNat zero succ = go
where
go n = if (n <= 0) then zero else succ (go (n - 1), n)
fact = paraNat 1 (\(r, n) -> n * r)
Let the types guide you. Here is your
foldNat, but with a type signature:Having another look at the
gohelper in your implementation offib, we can note the recursive case takes and returns a(Natural, Natural)pair. Comparing that with the successor argument tofoldNatsuggests we wantbto be(Natural, Natural). That is a nice hint on how the pieces ofgoshould fit:(I am ignoring the matter of strictness for now, but I will get back to that.)
This is not quite
fibyet, as can be seen by looking at the result type. Fixing that, though, is no problem, as Robin Zigmond notes:At this point, you might want to work backwards and substitute the definition of
foldNatto picture how this corresponds to an explicitly recursive solution.While this is a perfectly good implementation of
fib, there is one major difference between it and the one you had written: this one is a lazy right fold (as is the norm for Haskell catamorphisms), while yours was clearly meant as a strict left fold. (And yes, it does make sense to use a strict left fold here: in general, if what you are doing looks like arithmetic, you ideally want strict left, while if it looks like building a data structure, you want lazy right). The good news, though, is that we can use catamorphisms to define pretty much anything that consumes a value recursively... including strict left folds! Here I will use an adapted version of the foldl-from-foldr trick (see this question for a detailed explanation of that in the case of lists), which relies on a function like this:The idea is that we take advantage of function composition (
\n -> g (suc n)is the same asg . suc) to do things in the opposite order -- it is as if we swappedsuccandgoin the right hand side of your definition ofgo.lise succan be used as the successor argument tofoldNat. That means we will get ab -> bfunction in the end rather than ab, but that is not a problem because we can apply it to the zero value ourselves.Since we want a strict left fold, we have to sneak in a
($!)to make suresuc nis eagerly evaluated:Now we can define a strict left fold (it is to
foldNatwhatfoldl'fromData.Listis tofoldr):There is a final, important detail to deal with: making the fold strict is of little use if we are lazily building a pair along the way, as the pair components will remain being built lazily. We could deal with that by using
($!)along with(,)for building the pair in the successor function. However, I believe it is nicer to use a strict pair type instead so that we don't have to worry with that:The
!mark the fields as strict (note that you don't need to enableBangPatternsto use them).With everything in place, we can at last have
fibas a strict left fold:P.S.: As amalloy notes, your
faccalculates n^n rather than n!. That is probably a matter better left for a separate question; in any case, the gist of it is that factorial is more naturally expressed as a paramorphism on naturals, rather than as a plain catamorphism. (For more on that, see, for instance, the Practical Recursion Schemes blog post by Jared Tobin, more specifically the section about paramorphisms.)