In Haskell, it is idiomatic to write as much of your code in higher-order functions like folds, maps, and unfolds as possible. So what kinds of code can't be written with those higher-order functions? When is explicit recursion necessary?
When is explicit recursion necessary?
2.8k Views Asked by Ramith Jayatilleka At
2
There are 2 best solutions below
0

I think a lot of people find recursive data definitions easier to read than Mu/Fix/Nu types. It's not strictly necessary, but very useful there.
Similarly, you'll write the Foldable/Unfoldabe instances for such a data type by using recursion, but once those are provided, explicit recursion is not required going forward.
Let's assume we have a language without recursion or anything like it. This means no looping structures either. It also means we have (non-recursive) types as well so that we can't form a Y-combinator and escape. In this language, we are truly weak, separated from so many of our tools.
But we can ask a very good question about this language. Namely, what is the smallest thing we must give it in order for it to become just as powerful as a language with no such restrictions?
It turns out there are two answers.
We can introduce recursive binders, like a
let rec
command or something like Haskell'slet
which is alwayslet rec
. In other words, a structure which lets us definelet x = e in b
such that ifx
is free ine
then it is computed as a fixed point on the equationx = e
.We can introduce the function
fix :: (a -> a) -> a
such thatfix f
reduces in one step tof (fix f)
.It should be clear from the above presentation that
fix
can be implemented using recursive binders. What's a little less clear is that recursive binders can be implemented from non-recursive ones using fix, but here we are:The value
this
refers to the whole expression which ends up bound asx
which is just what we want.So why did I go out of my way to say all of the above?
Essentially, I'd like to argue that it's not possible to say that recursion is necessarily implemented via HOF combinators like
map
so long as you're willing to considerfix
on that list. I'd also like to argue that any recursion implemented by combinators in that set can be done "explicitly" using recursive binders. They're equally powerful.The interesting part comes in when you consider HOF combinators like
foldr
/unfoldr
by themselves. These are technically somewhat weaker thanfix
/recursive binders. The advantage is that if you build a programming language off only a select set offoldr
/unfoldr
-like principles then you can get a very rich, sub-Turing complete language which can be total or guaranteed to terminate.