Back to slide -- Keyboard shortcut: 'u'                      higher-order-fu-fall-15.scm - The forms discussed.Lecture 2 - slide 18 : 35
Program 1

"NEXT: Introduction to higher-order functions: flip"

(define (flip f)
  (lambda (x y)
    (f y x)))

(define flip
  (lambda (f)
    (lambda (x y)
      (f y x))))

(- 5 6)
((flip -) 5 6)
(cons 5 6)
((flip cons) 5 6)

"NEXT: Introduction to higher-order functions: negate"

(define (negate p)
  (lambda (x) 
    (not (p x))))

(define (is-even? x)
  (= (remainder x 2) 0))

(is-even? 5)
(is-odd? 5)

(define is-odd? (negate is-even?))
(is-odd? 5)

(< 5 6)
((negate <) 5 6)   ; UPS...

(define (negate p)
  (lambda x
    (not (apply p x))))

((negate <) 5 6)

"NEXT: compose"

(define (compose f g)
  (lambda (x)
    (f (g x))))

((compose is-even? (lambda (x) (* 2 x))) 3)

(define ff 
  (compose 
     (lambda (x) (* x x))
     (lambda (x) (+ x 1))))

(ff 5)

"NEXT: Linear search: find-in-list"

(define (find-in-list pred lst)
  (cond ((null? lst) #f)
        ((pred (car lst)) (car lst))
        (else (find-in-list pred (cdr lst)))))

(define lst (list #f 6.7 5 (cons 5 6) #\a (lambda(x) (* x 2))))

(find-in-list integer? lst)
(find-in-list real? lst)
(find-in-list boolean? lst)
(find-in-list pair? lst)
(find-in-list char? lst)
(find-in-list procedure? lst)

"NEXT: Selector functions: first, second, third, .."

(define (make-selector-function n)
  (lambda (lst) (list-ref lst (- n 1))))

(define first  (make-selector-function 1))
(define second (make-selector-function 2))
(define third  (make-selector-function 3))

(let ((lst (list 1 2 3 4 5)))
  (list (third lst) (second lst) (first lst)))


"NEXT: Mapping and filtering"

(define (mymap f lst)
  (if (null? lst)
      '()
      (cons (f (car lst))
            (mymap f (cdr lst)))))

(mymap is-even? (list 1 2 3 4 5 6 7))
(mymap (lambda (x) (* x 2)) (list 1 2 3 4 5 6 7))

(map is-even? (list 1 2 3 4 5 6 7))
(map (lambda (x) (* x 2)) (list 1 2 3 4 5 6 7))

(define (myfilter p lst)
  (cond ((null? lst) lst)
        ((p (car lst)) (cons (car lst) (myfilter p (cdr lst))))
        (else (myfilter p (cdr lst)))))

(myfilter is-even? (list 1 2 3 4 5 6 7 8))
(myfilter (negate is-even?) (list 1 2 3 4 5 6 7 8))

(define (iterative-filter pred lst)
  (reverse (filter-help pred lst '())))

(define (filter-help pred lst res)
  (cond ((null? lst) res)
        ((pred (car lst)) 
           (filter-help pred (cdr lst)  (cons (car lst) res)))
        (else 
           (filter-help pred (cdr lst)  res))))

(iterative-filter is-even? (list 1 2 3 4 5 6 7 8))
(iterative-filter (negate is-even?) (list 1 2 3 4 5 6 7 8))


"NEXT: Reduction and accumulation"

(reduce-right - (list 1 2 3 4 5))  ; undefined
(- 1 (- 2 (- 3 (- 4 5))))

(define (reduce-right f lst)
  (if (null? (cdr lst))
      (car lst)
      (f (car lst) 
         (reduce-right f (cdr lst)))))

(reduce-right - (list 1 2 3 4 5))
(reduce-right - (list 1))
(reduce-right - (list))

(reduce-left - (list 1 2 3 4 5))
(- (- (- (- 1 2) 3) 4) 5)

(define (reduce-left f lst)
  (reduce-help-left f (cdr lst) (car lst)))

(define (reduce-help-left f lst res)
  (if (null? lst)
      res
      (reduce-help-left f (cdr lst) (f res (car lst)))))

(reduce-left - (list 1 2 3 4 5))

(define (reduce-left f lst)  ; All in one
  (letrec ((reduce-help-left
             (lambda (f lst res)
                (if (null? lst)
                    res
                   (reduce-help-left f (cdr lst) (f res (car lst)))))))
    (reduce-help-left f (cdr lst) (car lst))))

(reduce-left - (list 1 2 3 4 5))
(reduce-left - (list 1))
(reduce-left - (list))


(define (accumulate-right f init lst)
  (if (null? lst)
      init
      (f (car lst) (accumulate-right f init (cdr lst)))))

(accumulate-right - 0 (list 1 2 3 4 5))
(accumulate-right - 0 (list 1))
(accumulate-right - 0 (list))

"NEXT: zip"

(define (zip z lst1 lst2)
  (if (null? lst1)
      '()
      (cons 
        (z (car lst1) (car lst2))
        (zip z (cdr lst1) (cdr lst2)))))

(zip cons (list 1 2 3) (list 'a 'b 'c))

"NEXT: Currying"

(define (curry2 f)
  (lambda(x)
    (lambda(y)
      (f x y))))

(- 1 2)
(((curry2 -) 1) 2)

(define (curry3 f)
  (lambda(x)
    (lambda(y)
      (lambda(z)
       (f x y z)))))

(- 1 2 3)
((((curry3 -) 1) 2) 3)

(define (uncurry2 f)
  (lambda (x y)
    ((f x) y)))

((uncurry2 (curry2 -)) 1 2)

(define (uncurry3 f)
  (lambda (x y z)
    (((f x) y) z)))


"NEXT: Continuation passing style"

(define (p-direct a b)
  (* (+ a b) (- a b)))

(p-direct 5 10)

(define (p-cps a b k0)
  (plus a b (lambda(v1)
              (sub a b (lambda(v2)
                         (mult v1 v2 k0))))))

(define (plus a b k) (k (+ a b )))
(define (sub a b k)  (k (- a b)))
(define (mult a b k) (k (* a b)))

(p-cps 5 10 (lambda (x) x))

(define (fact-direct n)
  (if (= n 0)
      1
      (* n (fact-direct (- n 1)))))

(fact-direct 5)

(define (fact-cps n k)
  (if (= n 0)
      (k 1)
      (fact-cps (- n 1)
                (lambda(v)       ; Eventually v becomes (fact (- n 1)). 
                  (k (* n v)))   ; Now pass (* n v) = (* n (fact (- n 1))) to k.
      )
  )
)

(fact-cps 5 (lambda (x) x))

(define (fact-tail-rec n r)
  (if (= 0 n)
      r
      (fact-tail-rec (- n 1) (* r n))))

(fact-tail-rec 5 1)

(define (fact-tail-rec-cps-1 n r k)
  (if (= 0 n)
      (k r)
      (fact-tail-rec-cps-1
        (- n 1)
        (* r n)
        (lambda (v)  ; Eventually v becomes (fact n), because the base case passes 
           (k v))    ; the result via a chain of trivial "pass on" functions.
                     ; Are all these (lambda(v) (k v)) functions really necessary?
      )              ; No - see the next variant called fact-tail-rec-cps-2.
  )
)

(fact-tail-rec-cps-1 5 1 (lambda (x) x))

(define (fact-tail-rec-cps-2 n r k)
  (if (= 0 n)
      (k r)
      (fact-tail-rec-cps-2
        (- n 1)
        (* r n)
        k           ; Eventually (fact n) is passed to k. k is the continuation 
      )             ; of the original call to the factorial function.
   )
)

(fact-tail-rec-cps-2 5 1 (lambda (x) x))

"NEXT: list-length"

(define (list-length lst)
   (cond ((null? lst) 0)
         ((pair? lst) (+ 1 (list-length (cdr lst))))
         (else 'improper-list)))

(list-length '(a b c))
(list-length '(a b c . d))

(define (list-length-direct lst)
  (call-with-current-continuation
   (lambda (do-exit)
     (letrec ((list-length-inner
                (lambda (lst)
                   (cond ((null? lst) 0)
                         ((pair? lst) (+ 1 (list-length-inner (cdr lst))))
                         (else (do-exit 'improper-list))))))
       (list-length-inner lst)))  ))

(list-length-direct '(a b c . d))

(define (list-length-cps lst k0)    ; Now CPS. k0 is the outer continuation - ready to catch exceptional values
  (letrec ((list-length-inner
             (lambda (lst k1) 
               (cond ((null? lst) (k1 0))
                     ((pair? lst) (list-length-inner
                                    (cdr lst)
                                    (lambda (v) (k1 (+ 1 v))) ; v is the length of (cdr l).
                                                              ; Pass 1+v to k1.
                                )
                     )
                     (else (k0 'improper-list)))) ))         ; Pass the symbol improper-list
                                                             ; to the outer continuation k0.
    (list-length-inner lst k0)))

(list-length-cps '(a b c . d) (lambda (x) x))

(define (list-length-iter-cps lst res k0)  ; CPS, but now iterative, tail-recursive.
  ; k0 is passed along the tail recursive calls, and
  ; can also be used for passing 'an exceptional value'.
  (cond ((null? lst) (k0 res))
        ((pair? lst) (list-length-iter-cps (cdr lst) (+ res 1) k0))
        (else (k0 'improper-list))))

(list-length-iter-cps '(a b c . d) 0 (lambda (x) x))
(list-length-iter-cps '(a b c d) 0 (lambda (x) x))

"THE END"