-
Some more tail recursion... →
Let’s continue with tail recursion and folding (recollect our previous post. Let’s use those concepts to write insertion sort algorithm. In an earlier post we wrote a recursive implementation of insertion sort algorithm as below:
Now, let’s write a tail recursive version of insertion sort. Let’s just call it
tr_isort
.Food for thought - is it possible to write a tail-recursive version of
insert
function that we used above? If yes, why don’t we try it. If no, why not? -
Tail recursions and reversing a list →
So, how about reversing a list using our
leftee
function from our previous post?Let’s work it out now. Here’s the original tail recursive function for your reference:
All you need to observe is how the accumulator
acc
changes - here we take a list element we are currently processing and stick it before (at the head) of the current accumulatoracc
.In most functional programming languages our
leftee
is actually calledfold_left
and is tail recursive. There’s also afold_right
which is not tail recursive, because of the way it applies the function to the list elements. More on this in a later post! -
More about auxiliary functions and recursions →
In an earlier posts, tail recursions were introduced using two very simple functions
tr_lst_sum
andtr_lst_rev
. In this post, let us carefully observe the structure of some simple tail recursive functions and see what they have in common. We will understand and use this information to write a generic function that can be used to write these other functions. Sounds like inception movie eh? Let’s get started!Here’s the tail recursive version of
lst_sum
to sum an input listlst
of elements.And here’s the tail recursive version of
lst_len
to compute the length of an input listlst
of elements.Let’s carefully observe the above two functions and try to understand the pattern - the recipe for such a computation. In both the functions,
- We have an initial accumulator (in this case the value is
0
but it could be anything in general) - We traverse the list, apply the auxiliary function to the initial value of the accumulator and a list element and compute a new value for the accumulator. 2.1. We do the above step to each element of the list (by calling the auxiliary function recursively/repeatedly on each element) and compute new values for the accumulator on the way
- When we are done with the entire list, we return the accumulator contents as the result
Now, if we just denote the auxiliary function by
faux
, it has a general shape -faux acc lst
- we do traverse the listlst
, but this is the general shape that we observe - callfaux
on the initial value of the accumulatoracc
and a list element and use the resulting value as the new value of the accumulator for the next call. For example, in the above functions the new values of the accumulators are(acc + h)
and(acc + 1)
. Now, let’s try to wrap this all into a single function, which we would call aleftee
- which would take three parameters - an accumulatoracc
, a functionf
to apply (to the accumulator and list element), and of course a listlst
to work on and will look likeleftee f acc lst
. We call itleftee
for a reason… (I think readers are already getting a hint as to where this is headed. Good!).As we see above the new value of the accumulator is the function applied to the current value of the accumulator
acc
and a list elementh
.Now, let’s rewrite
tr_lst_sum
andtr_lst_len
using ourleftee
:Here
( + )
is the function - just the addition operator. Isn’t it super concise? Aren’t you in love with this already?Food for thought - how would you use
leftee
to reverse an input list? - We have an initial accumulator (in this case the value is
-
An interesting podcast on work →
Lately, I have been thinking a lot about my work - my daily job. Most of us have one, where we slog every day, working late into the night or all night. We may have complaints, dissatisfactions, pleasant and unpleasant experiences, awesome career growths or non-existence of such a thing, lots of learning or nothing at all, great colleagues, teams, workplace issues, and the list goes on. I listened to an interesting podcast on “Meaning of work” from TED Radio Hour several months ago and listened to it once again over this weekend.
Whatever your situation is, this is a great podcast to listen to. And if you’re a manager, there are important lessons for you too, if you are someone willing to listen and learn. -
More examples using auxiliary functions →
Let’s look at a couple of more examples in order to get us thinking towards using auxiliary functions and accumulators while writing recursive functions. This would help us write tail-recursive functions which are safer and always a good practice. Note that some of the language compilers do not optimize tail recursions and so be aware of this fact in order not to be surprised when you do not see performance improvements while using tail recursive functions.
Let’s write the standard explode function
explode
that explodes a string into a list of characters. i.e., if you pass the string"hello"
, it would explode it and return the list['h'; 'e'; 'l'; 'l'; 'o']
.Let’s write another function
prime_factors
that would return all the prime factors of an input numbern
. Again, we shall use an auxiliary function to do the intermediate computations.That’s all for today! Hope it was enjoyable.