; filter is a built-in in later versions of Scheme,
; but we can write it ourselves!
(define (filter pred? lst)
  (cond ((null? lst) '())
        ((pred? (car lst))
         (cons (car lst) (filter pred? (cdr lst))))
        (else (filter pred? (cdr lst)))))


(define (test-my-type something)
  (cond ((number? something) number?)
        ((symbol? something) symbol?)
        ((list? something)   list?  )))

(define (like-the-first L)
  (filter (test-my-type (car L)) L))

(define (apply-all alof alon)
  (if (null? alof)
      '()
      (cons ((car alof) alon)
            (apply-all (cdr alof) alon))))

(define (make-counter)
  (let ((count 0))
    (lambda ()
      (set! count (+ 1 count))
      (display count)
      (newline))))

(define (make-counter-obj)
  (let ((count 0))
    (lambda (command)
      (cond ((eqv? command 'get) count)
            ((eqv? command 'inc) 
             (set! count (+ 1 count)))
            ((eqv? command 'reset)
             (set! count 0))))))

(define A (make-vector 5))
(vector-set! A 3 'something)

(define H (make-eqv-hashtable))
(hashtable-set! H 2 'something)
(hashtable-set! H (list 20 #f) 'crazy!)

(define (fib n)
  (if (<= n 1)
      n
      (+ (fib (- n 1))
         (fib (- n 2)))))

(define fib-memo
  (let ((memo (make-eqv-hashtable)))
    (define (fib-internal n)
      (cond [(<= n 1) n]
            [(hashtable-contains? memo n)
             (hashtable-ref memo n '())]
            [else
             (let ((val (+ (fib-internal (- n 1))
                           (fib-internal (- n 2)))))
               (hashtable-set! memo n val)
               val)]))
    fib-internal))

; old version, with global variable
;(define fib-hash (make-eqv-hashtable))
;
;(define (fib-memo n)
;  (cond ((not (hashtable-contains? fib-hash n))
;         (hashtable-set! 
;          fib-hash
;          n
;          (if (<= n 1)
;              n
;              (+ (fib-memo (- n 1))
;                 (fib-memo (- n 2)))))))
;  (hashtable-ref fib-hash n '()))

;; Sum of squares from 1 to n
(define (ssq n)
    (if (= n 0)
        0
        (+ (* n n)
           (ssq (- n 1)))))

;; Sum of squares using tail recursion
(define (ssq-better n accum)
  (if (= n 0)
      accum
      (ssq-better (- n 1)
                  (+ (* n n) accum))))

(define (fib-helper n i fib-of-i fib-of-i+1)
  (if (= i n)
      fib-of-i
      (fib-helper
       n
       (+ i 1)
       fib-of-i+1
       (+ fib-of-i
          fib-of-i+1))))

(define (fib-tail n) (fib-helper n 0 0 1))