Questions tagged [tailrecursion-modulo-cons]

Tail recursion modulo cons is similar to ordinary tail recursion, except that the recursive call is made inside a tail call to a data constructor. The optimization consists of the data record being allocated and partially filled _before_ making the recursive call which is to fill in the remaining part, as an effect -- thus becoming fully tail call.

Tail recursion modulo cons is similar to ordinary , except that the recursive call is made inside a tail call to a data cons tructor.

It was introduced by David H. D. Warren in the context of compilation of Prolog in 1980. It was described (though not named so) by Daniel P. Friedman and David S. Wise in 1974 as a LISP compilation technique.

If we first make the recursive call to find out its result, and only then create the data record to be returned holding that recursive result (as well as some additional, "local" data in other fields), the overall call is not tail. It would be tail, if not for the cons truction of that data record to be returned as the overall result.

Instead, that data record can be cons tructed (i.e. allocated and have all its local data fields filled) before the recursive call is made which fills the remaining slot.

This recursive call thus becomes actual tail call, open to tail call optimization.

In terms of e.g. lists this means building them in top-down manner, having the recursion extend the list's tail, as opposed to the bottom-up order where the recursive call builds the whole tail first and only then the head element is prepended to it, as in regular recursion.

It is thus closely related to co recursion, and to the "tail recursion with accumulator" technique, which itself is closely related to monoidal types of values where

   A + (B + (C + (D + (....))))  ==   (A + B) + (C + (D + (....)))
                                 ==  ((A + B) + C) + (D + (....))
                                 ==  ....

The prototypical example is list_copy in Prolog:

list_copy( [], [] ).
list_copy( [A|B], [A|C] ) :- list_copy( B, C ).

This is the consequence of rule's head being instantiated before its body is entered. The tail nature of the call becomes even clearer when re-written with explicit unifications,

list_copy( X, Y ) :- 
    X=[], Y=[]
    ;   %% (* OR *)
    X=[A|B], Y=[H|C], H=A, list_copy( B, C ).

See also:

14 questions
14
votes
2 answers

Tail-recursive bounded stream of pairs of integers (Scala)?

I'm very new to Scala, so forgive my ignorance! I'm trying to iterate of pairs of integers that are bounded by a maximum. For example, if the maximum is 5, then the iteration should return: (0, 0), (0, 1), ..., (0, 5), (1, 0), ..., (5, 5) I've…
Asim Ihsan
  • 1,501
  • 8
  • 18
13
votes
5 answers

Should I avoid tail recursion in Prolog and in general?

I'm working through "Learn Prolog now" online book for fun. I'm trying to write a predicate that goes through each member of a list and adds one to it, using accumulators. I have already done it easily without tail…
12
votes
2 answers

F# PurelyFunctionalDataStructures WeightBiasedLeftistHeap ex 3.4

I'm working on Okasaki's Purely Functional Data Structures and trying to build F# implementations of things. I'm also going through the exercises listed in the book (some are pretty challenging). Well I'm stuck on exercise 3.4 which calls for…
9
votes
3 answers

Will this Haskell code take too much memory?

As in this code: import Data.Char groupsOf _ [] = [] groupsOf n xs = take n xs : groupsOf n ( tail xs ) problem_8 x = maximum . map product . groupsOf 5 $ x main = do t <- readFile "p8.log" let digits = map digitToInt $concat $ lines t …
McBear Holden
  • 5,741
  • 7
  • 33
  • 55
9
votes
5 answers

tail-recursive function appending element to list

i've seen several examples of implementing append an element to a list, but all are not using tail recursion. how to implement such a function in a functional style? (define (append-list lst elem) expr)
8
votes
5 answers

Run-time complexities for recursive algorithms

I've searched high and low and can't seem to find a lot of material related to run-time complexities, recursion, and java. I'm currently learning run-time complexities and Big-O notation in my Algorithms class, and I'm having trouble analyzing…
7
votes
2 answers

Tail-recursion optimization in Oz

In the chapter about function in the Oz tutorial, it says that: similar to lazy functional languages Oz allows certain forms of tail-recursion optimizations that are not found in certain strict functional languages including Standard ML, …
5
votes
1 answer

Why can Tail Recursion Modulo Cons be optimized?

For example, this is not a tail call : map _ [] = [] map f (x : xs) = f x : map f xs the recursive callis guarded by the (:) data constructor, so it won't build up a huge stack like an equivalent in some other language might do. It works like this…
3
votes
2 answers

Prolog translation of Lisp's tail-recursion

I have a question that is a followup to a previous topic, Should I avoid tail recursion in Prolog and in general? In the above linked article , user false provided this code example and this explanation ... Back in the 1970s, the major AI language…
3
votes
2 answers

scheme tail recursion

I am trying to create a scheme tail recursive function flatten-tl-rec that flattens a nested list of lists. (define flatten-tl-rec (lambda (xs) (letrec ([flatten-tl-rec-acc (lambda (xs acc) (cond ((empty? xs)…
omega
  • 40,311
  • 81
  • 251
  • 474
3
votes
2 answers

Explanation of a Prolog algorithm to append two lists together

This is an algorithm to append together two lists: Domains list= integer* Predicates nondeterm append(list, list, list) Clauses append([], List, List) :- !. append([H|L1], List2, [H|L3]) :- append(L1, List2, L3). Goal append([9,2,3,4],…
1
vote
3 answers

Tail call optimization with a function returning a tuple

I have a simple function that splits a list at an index: let rec split_at ls i = match i with | 0 -> ([], ls) | _ -> match ls with | [] -> raise Not_found | h::t -> match split_at t (i - 1) with | (left, right) -> ((h…
mushroom
  • 6,201
  • 5
  • 36
  • 63
1
vote
1 answer

Can we implement tail recursion modulo cons et al. through trampolines?

You can regard trampolines as compiler optimizations reified in the program. So what is stopping us from adapting more general optimization techniques in exactly the same manner. Here is a sketch of tail recursion modulo cons: const loop = f =>…
0
votes
0 answers

Tail recursion with the State and CPS monads?

I am in the process of creating a simple parsing library in Haskell, which compiles down the parser specification to optimized code using Template Haskell. However, I am trying to figure out what kind of code is the most efficient to optimize to, so…