We saw last time:
(define (add2 n)
   (+ n 2))
Is actually just shorthand -- "syntactic sugar" -- for
(define add2
  (lambda (n)
     (+ n 2)))
We can use functions w/o naming them:
;; filter-vs: (alpha, beta -> boolean), beta, list-of-alpha --> list-of-alpha
;; ...


; Example of using filter-vs: Remove all elements of the list divisible by 5:
;
(filter-vs (lambda (x y) (zero? (remainder x y))) 5 (list 4 5 11 0 10 -5 6))

So filter-vs takes in a binary function comparer and some sort of reference k; can we roll k inside the comparer? Sure! Write filter-in from scratch: it takes a predicate (good?: alpha --> boolean), and a list, and returns a list of all the elements considered good.
Exercise: Write filter-vs, in terms of filter-in. (Trivial in a math-ish sense. Can the other direction also be written so trivially?)

Note: "collect" might be a better name than "filter", since we collect the good ones, not filter them out. Alas, filter is already the name of the scheme built-in. Perhaps we could just use our own names, filter-in and filter-out:

(define filter-in filter)

;; filter-out: (alpha -> boolean), list-of-alpha --> list-of-alpha.
;;
(define (filter-out bad? elts)
  (local [(define (good? elt) (not (bad? elt)))]
    (filter-in good? elts)))
Observe the contracts we put in.

(define (make-adder n)
  (lambda (y) (+ n y)))

((make-adder 19) 4) = 3
(map (make-adder 19) (list 4 5 6)) = (list 23 24 25)

(define add19 (make-adder 19))

(End review)

make-adder is an example of something called "Currying": Example: Addition takes 2 arguments. However, consider add19 -- essentially, it is addition where you've already given the first number to add, but not the second. The function encapsulates the first arg, and you give the second arg not to +, but to this function.
We say that make-adder is a curried version of addition. I'm not concerned about you remembering the term, but you'll find it's a handy concept.

Currying also means that: once you have functions as values, really you can view all function as one-argument functions. +: num, num --> num we can think +: num --> (num --> num). Similarly, draw-solid-disk : posn, number, color --> true can be viewed of as draw-solid-disk: posn --> (number --> (color --> true)). This is helpful because if we can prove our program always handles all functions-of-one-argument correctly, then by using this trick we can show we handle functions of any "arity". (This is handy if you're writing a compiler or designing a language which provably has good properties.) Named for Haskell Curry (1900-1982), logician. The language Haskell also honors his name; functions in Haskell always take one argument. Note to self, ian: does Haskell allow 0-arg functions?

Exercise: write filter-vs, just using filter.

Exercise: write filter, just using filter-vs.

Exercise: Write the function negate, which takes in a boolean function, and returns that function's complement. First, what's even the contract for this thing?

Write the function apply2x; e.g. (apply2x square 5) = (square (square 5)) = (square 25) = 625. Really, we want to transform such a function like square, into one which applies it twice: (define raise4th (double-fun square)) (Alternately, you could apply reverse twice (not too helpful), or remove-largest-from-list, or translate-shape, or ...
(If bored by this example -- write out iterate: a version that takes in n, and returns f^n (that is, a function which itereates f, n times.)

The Last List Function You'll Ever Need

We have seen handy functions built out of smaller ones: map, filter take in functions, and do common list-ish things. Can we take it further? A pattern we've seen over and over again is the List template. What changes for every list function? What stays the same? Can we keep the static parts, and instead just pass the little bits that differ?

Ian: re-write list functions to just call a helper (after all 3 template steps); show several examples, and then abstract to arrive at foldr.

This Ultimate List Function ("ulf") needs two inputs: the base case, and a rule to combine the first of the list with the result of the recursive call. Before we write the function, lets make some test-cases:

(ulf + 0 (list 3 7 2)) = 12   ; sum the list
(ulf (lambda (x y) (or (symbol=? x 'pineapple) y))
     false
     (list 'apples 'oranges 'pineapple 'gravy))    = true
(ulf (lambda (x y) (or (symbol=? x 'pineapple) y))
     false
     (list 'apples 'oranges 'pinenuts  'gravy))    = false

;; You try one: How about all-even?.





;; Or, max.  (use negative infinity, #i-inf.0, as the base case.)





Okay, let's tackle the function now.
;; ulf: process any list, a la the template.
;; combine-rule: A function which will be given first item
;;               and the result of the recursive call.
;; base-case: What to return on an empty list.
;; some-list: the actual list to process.
;; Like any list-processing function, except that
;; we're given the base case,
;;
(define (ulf combine-rule base-case some-list)
  (local [(define (the-list-fun a-list)
            (cond [(empty? a-list) ..]
                  [(cons?  a-list) ..(first a-list)..
                                   ..(the-list-fun (rest a-list))..]))]
    (the-list-fun some-list)))







The contract for ulf isn't trivial:
;; ulf: (alpha, beta --> beta), beta, list-of-alpha  --> beta
Note: ulf also known as foldr.

Exercise: write map, using foldr.

Exercise: write ulf without using local!

There is also a version foldl, which folds left-to-right, rather than right-to-left. If foldr was the straight template, then foldl is the canonical accumulator-style program for lists.

(define (foldl combine base lyst)
  (local [(define (accum-help accum stuff)
            (cond [(empty? stuff) accum]
                  [(cons?  stuff) 
                   (accum-help (combine (first stuff) accum) (rest stuff))]))]
    (accum-help base lyst)))

See lect18-find.ss for a version of find which actually acceses the disc, and uses functions like map, filter, fold, to help.