;
;	Solutions for HomeWork 1.
; 	
;	Each posted solution is most common or unique solution.
;

;----------------------------------------------------------------
; Exercises 2.2.7
; 1. (duple n x) returns a list containing n copies of x
; 

(define	duple 
	(lambda (n x)
		(if (and (integer? n) (> n -1))
		   	(if (= n 0) 	'()
					(cons x (duple (- n 1) x)))
			(write "wrong parameters")))) 

;----------------------------------------------------------------
; 2. (invert lst), where lst is a list of 2-lists(lists of 
;    length two), returns a list with each 2-list reversed.
;

(define	invert (lambda	(lst)	(map reverse lst)))

;----------------------------------------------------------------
; 3. (list-index s los) returns the zero-based index of the first
;    occurence of s in los, or -1 if there is no occurences of s in los.
;

;    suggested by Ian Murdock. same idea with Gongyuan Zhuang

(define list-index
        (lambda (s los)
                (if (null? los)
                        -1
                        (if (eq? (car los) s)
                                0
                                (if (= (list-index s (cdr los)) -1) 
                                        -1
                                        (+ 1 (list-index s (cdr los)))))))) 


;    The following two solutions are most general.

;    uses a helper function : list_index_aux
(define	list_index_aux 
	(lambda (s los n)
		(if (null? los)
			-1
			(if (eq? s (car los)) 
				n
				(list_index_aux s (cdr los) (+ n 1)))))) 
(define list_index
	(lambda (s los)	
		(list_index_aux s los 0)))
		

;    uses letrec.
(define list-index
	(lambda (s los)
		(letrec ((index_index_aux (lambda (ind los)
					(cond ((null? los)? -1)
					      ((eq? s (car los)) ind)
					      (else (index (+ ind 1) (cdr los)))
					))))
		(index_index_aux 0 los))))

;---------------------------------------------------------------------
; 4. (vector-index s vos) returns the zero-based index of the first
;    occurrnce s in vos, or -1 if there is no occurrence of s in vos. 
;

(define vector-index
	(lambda (s vos)
		(list-index s (vector->list vos))))

;---------------------------------------------------------------------
; 5. (ribassoc s los v fail-value) returns the value in v that is
;    associated with s, or fail-value if there is no associated value.
;

(define	ribassoc
	(lambda (s los v fail-value)
		(if (eq? (list-index s los) -1) 
			fail-value
			(vector-ref v (list-index s los)))))

;    uses let.
(define ribassoc
	(lambda (s los v fail-value)
		(let ((ind (list-index s los)))
			(if (= ind -1) 
				fail-value
				(vector-ref v ind)))))

;---------------------------------------------------------------------
; 6. (filter-in p lst), where p is the predicate, returns the list that
;    satisfy the predicates
;

;    recursive call
(define filter-in
	(lambda (p lst)
		(if (null? lst) 
			'()
			(if (p (car lst))
				(cons (car lst) (filter-in p (cdr lst)))
				(filter-in p (cdr lst))))))
		
;    suggested by Valerio Pascucci.
(define filter-in
	(lambda (p lst)
		(apply append 
			(map (lambda (x) (if (p x) (list x) '())) lst))))
		

;---------------------------------------------------------------------
; 7. (product los1 los2) returns a list of 2-lists that represents
;     that cartisian product of los1 and los2.
;

;    suggested by Yao Feng 
;    uses a helper function.

(define product_aux
	(lambda (s los)
		(if (null? los)
			'()
			(cons (list s (car los)) 
			      (product-aux s (cdr los))))))
(define product
	(lambda (los1 los2)
		(if (null? los1)
			'()
			(append (product_aux (car los1) los2)
				(product (cdr los1) los2)))))

;    suggested by Lin Chen
(define product
	(lambda (los1 los2)
		(if (null? los1) '()
		    (if (null? los2) '()
			(cons (list (car los1) (car los2))
			      (append (product (list (car los1)) (cdr los2))
				      (product (cdr los1) los2)))))))

;    suggested by Valerio Pascucci.
(define product
	(lambda (los1 los2)
		(apply append
			(map (lambda (los_i)
				(map (lambda (los_j) (list los_i los_j)) 
				      los2)) 
			      los1))))

;---------------------------------------------------------------------
; 8. (swapper s1 s2 slst) returns a list the same as slst, but
;    with all occurrences of s1 replaced by s2 and all occurrences
;    of s2 replaced by s1.

;    suggested by Nitin Garg
(define swapper
	(lambda (s1 s2 slst) 
	(cond 
		((null? slst) '())
		((atom? (car slst)) (cond 
			((eqv? s1 (car slst)) 
				(cons s2 (swapper s1 s2 (cdr slst))))
			((eqv? s2 (car slst))
				(cons s1 (swapper s1 s2 (cdr slst))))
			(else (cons (car slst) (swapper s1 s2 (cdr slst))))))
		(else (cons (swapper s1 s2 (car slst))
			    (swapper s1 s2 (cdr slst)))))))

;---------------------------------------------------------------------
; 9. (rotate los) returns a list similar to los, except that the
;    last element of los becomes the first in the returned list.
;

;    uses two helper functions
(define last
	(lambda (los)
		(if (null? los) '()
		    (list-ref los (- (length los) 1)))))
(define	rest
	(lambda (los)
		(if (null? los) '()
		    (if (null? (cdr los)) '()
		   	(cons (car los) (rest (cdr los)))))))
(define rotate
	(lambda (los)
		(if (null? los) '()
		    (cons (last los) (rest los)))))

;    suggested by Shin Chang
(define rotate
	(lambda (los)
		(if (null? los) '()
		    (if (null? (cdr los)) los
			(cons (car (rotate (cdr los)))
			      (cons (car los) (cdr (rotate (cdr los)))))))))

;---------------------------------------------------------------------
; Exercises 2.2.8
; 1. (down lst) wraps parentheses around each top-level element of los.
;

(define down
	(lambda (lst)
		(if (null? lst) '()
		    (cons (cons (car lst) '()) (down (cdr lst))))))

;    suggested by Valerio Pascucci
(define down (lambda (lst) (map list lst)))

;---------------------------------------------------------------------
; 2. (up lst) removes a pair of parentheses from each top-level element
;    of lst. If a top level element is not a list, it is included in the
;    result, as is.
;

(define up
	(lambda (lst)
		(if (null? lst) '()
		    (if (list? (car lst))
			(append (car lst) (up (cdr lst)))
			(cons (car lst)(up (cdr lst))))))) 

;     suggested by Valerio Pascucci
(define up
	(lambda (lst)
		(apply append 
		       (map (lambda (x) (if (list? x) x (list x))) lst))))

;---------------------------------------------------------------------
; 3. (count-occurrences s los) returns the number of occurrences of s 
;    in los.


(define count-occurrences
	(lambda (s slst)
		(if (null? slst) 0
		    (if (symbol? (car slst))
		        (if (eq? s (car slst))
			    (+ 1 (count-occurrences s (cdr slst)))
			    (count-occurrences s (cdr slst)))
			(+  (count-occurrences s (car slst))
			    (count-occurrences s (cdr slst)))))))

;---------------------------------------------------------------------
; 4. (flatten slst) returns a list of the symbols contained in slst
;    in the order in which they occur. Intuitively, flatten removes
;    all the inner parentheses from its argument.
;

(define flatten
	(lambda (slst)
		(if (null? slst) '()
		    (if (symbol? (car slst))
			(cons (car slst)(flatten (cdr slst)))
			(append (flatten (car slst)) (flatten (cdr slst)))))))

;---------------------------------------------------------------------
; 5. (merge lon1 lon2), where lon1 and lon2 are lists of numbers that
;    are sorted in ascending order, returns a sorted list of all the
;    numbers in lon1 and lon2.
;

(define merge
	(lambda (lon1 lon2)
		(if (null? lon1) lon2
		    (if (null? lon2) lon1
			(if (<= (car lon1) (car lon2))
			    (cons (car lon1) (merge (cdr lon1) lon2))
			    (cons (car lon2) (merge lon1 (cdr lon2))))))))
					

