; -- Exercise 1.2.1
; Evaluate each expression

(define x '(a b ((3) c) d))

(car (cdr x))
; Value: b

(caddr x)
; Value: ((3) c)

(cdaddr x)
; Value: (c)

(char? (car '(#\a #\b)))
; Value: #t

(cons 'x x)
; Value: (x a b ((3) c) d)

(cons (list 1 2) (cons 3 '(4)))
; Value ((1 2) 3 4)

(cons (list) (list 1 (cons 2 '())))
; Value (() 1 (2))


; -- Exercise 1.2.2
; Evaluate each expression

(define x1 '(a b))
(define x2 '(a))

(define x3 (cons x1 x2))
x3
; ((a b) a)

(eq? x3 (cons x1 x2))
; Value: #f

(eq? (cdr x3) x2)
; Value: #t

(cons (cons 'a 'b) (cons 'c '()))
; Value: ((a . b) c)

(cons 1 (cons 2 3))
; Value: (1 2 . 3)


; -- Exercise 1.2.3
; Evaluate each expression

(define v1 (vector (cons 1 2) 3))
(define v2 (vector 'a v1))

v2
; Value: #2(a #2((1 . 2) 3))

(define v3 '#(a #((1 . 2) 3)))
(eq? v2 v3)
; Value: #f

(eq? v1 (vector-ref v2 1))
; Value: #t

(eq? (vector-ref v1 0)
     (vector-ref (vector-ref v2 1) 0))
; Value: #t


; -- Exercise 1.3.1
; What is unusual about the following expression?
((lambda (x) (list x (list (quote quote) x)))
 (quote (lambda (x)
	  (list x (list (quote quote) x)))))

; First, this S-expression is an application. 
; (quote (lambda (x) (list x (list (quote quote) x))))
; is the parameter to the one-argument lambda
; (lambda (x) (list x (list (quote quote) x)))

; Therefore, x is lambda-bound to:
; '(lambda (x) (list x (list (quote quote) x)))

; By substitution, the body of the lambda is:
; (list
;   '(lambda (x) (list x (list (quote quote) x)))
;    (list (quote quote)
;          '(lambda (x) (list x (list (quote quote) x)))))

; Because scheme is an applicative order evaluator,
; the arguments to the outer list must be evaluated.

; The first argument is a quote list and evaluates to:
; (lambda (x) (list x (list (quote quote) x)))

; The second argument is a call to list, 
; again its parameters must be evaluated.
; The first parameter (quote quote) evaluates to 
; "quote"
; The second parameter is a quoted list and evaluates to:
; (lambda (x) (list x (list (quote quote) x)))
; Now this call to list evaluates to:
; (quote (lambda (x) (list x (list (quote quote) x))))

; Therefore, the two arguments to the outer list 
; evaluate to:
; Arg 1 := (lambda (x) (list x (list (quote quote) x)))
; Arg 2 := (quote (lambda (x) (list x (list (quote quote) x))))

; And the outer list evaluates to:
; ((lambda (x) (list x (list (quote quote) x)))
;  (quote (lambda (x) (list x (list (quote quote) x)))))

; Therefore this expression evaluates to itself
; Value: 
; ((lambda (x) (list x (list (quote quote) x))) 
; (quote (lambda (x) (list x (list (quote quote) x)))))


; -- Exercise 1.3.2
; Here's an implementation of cells

(define cell-tag "cell")

(define make-cell (lambda (x) (vector cell-tag x)))

(define cell?
  (lambda (x)
    (if (vector? x)
	(if (= (vector-length x) 2) 
	    (eq? (vector-ref x 0) cell-tag)
	    #f)
	#f)))

(define cell-ref
  (lambda (x)
    (if (cell? x)
	(vector-ref x 1)
	(display "Invalid argument to cell-ref"))))

(define c (make-cell 5))
c
; Value: #2("cell" 5)

(cell? c)
; Value: #t

(cell-ref c)
; Value: 5


; -- Exercise 1.3.3
; Consider two or three languages you know or for 
; which you can find documentation.  What restrictions, 
; if any, are imposed on procedures that keep them 
; from being first class?  Is it possible to create 
; anonymous procedures?

; The C (Procedural) Programming Language 
; In C, you can assign functions to variables because 
; you can declare function pointers and assign those 
; to structs or variables.
; You can not, however, return functions created 
; within functions because anonymous functions can 
; not be created in C.

; The Java (Object-Oriented) Programming Language
; In Java, you can create anonymous functions because 
; you can write Java code to disk, compile that code, 
; and load it without knowing the name of the function 
; at compile time.  You can not, however, assign 
; functions to variables because even the function 
; pointer hack of C is not available in Java.


; -- Exercise 1.3.4
; Write a procedure curry2 that takes a procedure of 
; two arguments and returns a curried version of the 
; procedure that takes the first argument and returns 
; a procedure that takes the second argument.

(define (curry2 f)
  (lambda (a) 
    (lambda (b)
      (f a b))))

(((curry2 +) 1) 2)
; Value: 3

(define consa ((curry2 cons) 'a))
(consa '(b))
; Value: (a b)


; -- Exercise 1.3.5
; Write a curried version of compose. 
; Can you think of a use for it?

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

(define (f x) (* x x))
(define (g x) (sqrt x))
((compose f g) 4)

(define ccompose
  (lambda (f)
    (lambda (g)
      (lambda (x)
	(f (g x))))))

(((ccompose f) g) 4)


; -- Exercise 1.3.6
; With automatic cyrring if a procedure is passed 
; fewer arguments than it expects, it simply returns 
; a procedure that takes the rest of the arguments. 
; What are the advantages and disadvantages of 
; automatic currying?


; -- Exercise 1.3.7
; Define a version of compose that takes as arguments
; either two or three procedures (of one argument) 
; and composes them.

(define compose2or3
  (lambda x
    (if (= (length x) 3)
	(compose (car x) (compose (cadr x) (caddr x)))
	(compose (car x) (cadr x)))))

(define (h x) (+ x 1))
((compose2or3 f g) 4)
((compose2or3 f g h) 4)


