This lab is to review the use of recursion to compute with lists, and to contrast it with the way map and apply do similar things.
Note: The functions cross, filter-in, filter-out and comes-before? you define in problems in the last problems are really useful!

Recursion vs. map/apply where either is fine

Write functions (max-sin-r L) and (max-sin-f L) that both take a list L = (x1 x2 ... xn) and return the largest number amongst sin(x1), sin(x2), ..., sin(xn). The function (max-sin-r L) must be defined recursively, without the aid of map and apply. The function (max-sin-f L) may not use recursion or call any recursive function you write, it must use map and apply instead. Examples:
> (max-sin-r '(3 4 7 8 10 12))
0.9893582466233818
> (max-sin-f '(3 4 7 8 10 12))
0.9893582466233818
> (max-sin-f '(5.5))
-0.7055403255703919
> (max-sin-r '(5.5))
-0.7055403255703919

Where recursion works more naturally

Define a function (arg-max-sin L) that returns the element of L with the largest sin(.) value amongst all elements of L. Note: I suggest using recursion! In the following example
> (sin-max '(2.5 2.0 1.5 1.0))
1.5
we get 1.5 because the sin(1.5) = 0.9974949866040544, which is larger than the sines of all the other values. Think about this: why is it hard to use map/apply for this problem?

Currying

Thinking back on lambda and expressions that evaluate to functions, there's an interesting and common use of lambda that's important enough to get a name: Currying. If you have a function f that takes n arguments, and you produce a new function of n-1 arguments by fixing the value of one of n's arguments, that's called currying. It's probably easier to see in action. Suppose I want to define a function increase-all that takes a list of numbers and an amount delta, and increases all elments of the list by delta.
> (define (increase-all L delta) (map (lambda (x) (+ x delta)) L))
> (increase-all '(4 2 9 6) 2)
'(6 4 11 8)
Notice the expression (lambda (x) (+ x delta)). It is turning the binary function x + y into the unary function x + delta by fixing the value of the parameter y. That's currying. It turns out to be a useful thing to do in a lot of circumstances.

Write a function called (cross A B) that takes two lists, A and B, and returns the list of all pairs of elements whose first componant comes from A and second componant comes from B. For example:

> (cross '(1 2 3) '(a b))
((1 a) (1 b) (2 a) (2 b) (3 a) (3 b))
> (cross '(hi) '(bye there))
((hi bye) (hi there))
      
Here are some words of wisdom: Wouldn't it be useful to have a function (pair-with x L) that takes an object x and a list L = (l1 l2 ... lk) and returns the list ((x l1) (x l2) (x l3) ... (x lk))? Both in defining this function and in using it, you have a choice of map/apply and recursion. What are the tradeoffs? Note: defining pair-with using map is pretty easy if you make use of the idea of currying.

Filtering

Write functions (filter-in keep? L) and (filter-out reject? L) that take a predicate and a list and return a list that either keeps only elements that the predicate keep? evaluates to true on or keeps everything except what reject? evaluates to true on. Here are some examples:
> (filter-in even? '(10 9 8 7 6 5 4 3 2 1))
(10 8 6 4 2)
> (filter-out even? '(10 9 8 7 6 5 4 3 2 1))
(9 7 5 3 1)
> (filter-out null? '( (a b) () (1 2 3) ("the" "end") () (x y z)))
((a b) (1 2 3) ("the" "end") (x y z))
> 
	
Note: You'll need to do this by recursion ... at least one of them. However, a clever person could use these to solve the sin-max problem.

The member function

The member function in scheme is pretty useful. The call (member x L) searches for x in the list L by taking the cdr of L repeatedly until it either runs out, in which case #f is returned, or until it gets to a point where x is the car of whatever's left of L, in which case this remaining sublist is what's returned. For example:

> (member 'd '(a b c d e f))
(d e f)
> (member 'x '(a b c d e f))
#f	    
Using member, write a function comes-before? that takes a list L, and two objects a and b, and returns #t if a comes before b in the list, and #f otherwise. For example:
> (comes-before? 'mon 'wed '(sun mon tue wed thu fri sat))
#t
> (comes-before? 'fri 'wed '(sun mon tue wed thu fri sat))
#f
> 

Submit

You will submit the file scheme04.scm to the submit system. Make sure that anything that is not a function definition is commented out, so that there is no output when the script is executed. You will submit as:
submit -c=si413 -p=scheme04 scheme04.scm

Christopher W Brown