; Def'n:   tail-recursion:
; A function is tail-recursive if the result of the recursive call 
; gives exactly the result for the original function call,
; without any further processing.
;
; This is a good feature because it means a smart implementation does
; *not* need to build up all the pending evaluations.
; In machine architecture, this corresponds to not needing to allocate
; a new stack frame on each recursive call -- just update the
; parameters and do an assembly-code JMP back up to the start of the function.
;
; Hey, that's how loops are implemented!
; UPSHOT: Loops are a special, constrained form of recursion (tail-recursion).
; If you have a language w/ recursion but not loops, you don't worry,
; because you can just use tail-recursion.
; However, the reverse is not easy: If you have a language with
; loops but no recursion, the only way to get recursion is to
; (essentially) keep track of the call-stack yourself.
; [This clearly *can* be done: early assembly-languages didn't have a
;  "JSR" (jump-to-subroutine) instruction, and yet they could implement
;  Lisp in 1965.]
;
; The scheme language standard *requires* that tail-recursive functions
; be safe-for-space [essentially, that they turn tail-recursion into loops
; at the assembly language level].
;
; (Technical aside: ; more properly, we should say 
; "A function's *body* is tail-recursive if 
; all its recursive calls are in tail-position".
; "body" because we are talking about a static, syntactic property
; that depends only on the program source-text.
; Since "...without any further work" is a *run*-time concept,
; it's not quite technically correct.
; However, it's good enough for this class; it captures the essence of
; "a call to this function can be evaluated w/o building up stack frames",
; a property also known as "safe for space" (that is, a function
; that can be solved in O(1) memory won't require O(n) memory).)


; SO:
; Let's convert a non-tail-recursive function to tail-recursion:
;  sum-v1 and sum-v2, in Java.
;

; sum-v2, in scheme

; Exercise: write a tail-recursive version of my-min.




(define (sum-v2 data sum-so-far)
  (cond [(empty? data) sum-so-far]
        [(cons? data) (sum-v2 (rest data)
                              (+ sum-so-far (first data)))]))


(check-expect (sum-v2 (list 5 2 4 1) 0) 12)

(define-struct foo (a b))
(check-within (make-foo 2.1 2.2) (make-foo 2.2 #e2.3) 0.8)

(define (sum-v1 data sum-so-far)
  (cond [(empty? data) 0]
        [(cons? data) (+ (first data)
                         (sum-v2 (rest data)))]))