Reputation: 1639
I'm solving problem 4 in the 99 problems of Ocaml and I'm still learning OCaml
Question 4 reads
OCaml standard library has List.length but we ask that you reimplement it. Bonus for a tail recursive solution.
So as per my understanding a recursive solution merits bonus points because it more efficient than a potentially easier more verbose solution
I came up with this for a tail recursive solution
let length in_list =
let rec find_len cur_length = function
| [] -> cur_length
| hd::tl -> find_len (cur_length + 1) tl
in find_len 0 in_list
;;
And as per my understanding of tail recursion this is valid because it operates recursively on the tail
My question is what is the opposite of this? What is a valid non tail recursive solution
I guess it would be something that operates recursively on the head of the list I came up with
let hd_rec_length in_list =
let rec pop_last saved_list= function
| [] -> saved_list
| [last] -> saved_list
| hd::tl -> pop_last (saved_list@[hd]) tl
in
let rec hd_rec_find_len cur_length in_list =
match in_list with
| [] -> cur_length
| hd::tl -> hd_rec_find_len (cur_length+1) (pop_last [] in_list)
in hd_rec_find_len 0 in_list
;;
But my gut tells me I'm missing something more obvious than this and the second solution seems like too much work and the first seems more natural and easy, what am I missing?
Upvotes: 1
Views: 703
Reputation: 370112
A tail-recursive function is a recursive function where all recursive calls happen in a tail position. What that means is that the recursive call must be the last thing that happens in any given path through the function. All of the recursive functions in your question are tail recursive.
Tail recursion does not mean recursing on the tail of the list. In fact a tail recursive function doesn't have to involve lists at all.
So a non-tail recursive function would be any function where you do anything after the recursive call (or there are even multiple recursive calls that aren't mutually exclusive). Usually that means applying some other function to the result of the recursive function after the recursive function returns.
A non-tail recursive version of length
would be:
let rec length = function
| [] -> 0
| _::tl -> 1 + length tl
This is not tail-recursive because the last thing that happens here is the addition, not the call to length
. So after the recursive call returns, we add 1 to its result and then we return as well.
Upvotes: 5