a tail-recursion version list appending function

后端 未结 5 2137
猫巷女王i
猫巷女王i 2020-12-04 01:44

i see 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

5条回答
  •  离开以前
    2020-12-04 02:17

    The following is an implementation of tail recursion modulo cons optimization, resulting in a fully tail recursive code. It copies the input structure and then appends the new element to it, by mutation, in the top-down manner. Since this mutation is done to its internal freshly-created data, it is still functional on the outside (does not alter any data passed into it and has no observable effects except for producing its result):

    (define (add-elt lst elt)
      (let ((result (list 1)))
        (let loop ((p result) (lst lst))
          (cond 
            ((null? lst) 
               (set-cdr! p (list elt)) 
               (cdr result))
            (else 
               (set-cdr! p (list (car lst)))
               (loop (cdr p) (cdr lst)))))))
    

    I like using a "head-sentinel" trick, it greatly simplifies the code at a cost of allocating just one extra cons cell.

    This code uses low-level mutation primitives to accomplish what in some languages (e.g. Prolog) is done automatically by a compiler. In TRMC-optimizing hypothetical Scheme, we would be able to write the following tail-recursive modulo cons code, and have a compiler automatically translate it into some equivalent of the code above:

    (define (append-elt lst elt)              ;; %% in Prolog:
      (if (null lst)                          ;; app([], X, Z) :- Z=[X].
        (list elt)                            ;; app([A|B], X, Z) :-
        (cons (car lst)                       ;;   Z=[A|Y],         % cons _before_
              (append-elt (cdr lst) elt))))   ;;   app( B, X, Y).   % tail call
    

    If not for the cons operation, append-elt would be tail-recursive. This is where the TRMC optimization comes into play.

提交回复
热议问题