함수 사용하는 방법은 (procedure arg1 arg2 ...)의 형태가 된다. (+ 1/2 1/2) => 1 여러 값을 포함하는 데이터 구조로 list가 있다. list는 괄호 안에 여러 값들을 적는다. (1 2 3 4 5) list에 다양한 type이 올 수 있다.(참고: haskell의 경우는 같은 type만이 올 수 있다.) (4.2 "hi") procedure와 단순 list를 구별하는 방법은 어떻게 할까? 이를 위해 quote가 있다. quote를 사용하면 quote 뒤에 오는 것은 procedure가 아니라 단순 list의 data라는 것을 알린다. 예: (quote (+ 3 4)) => (+ 3 4) quote에 대한 축약으로 '(single quotation mark)를 사용할 수 있다. '(/ (+ 2 -1) 3) => (/ (+ 2 -1) 3) list에 관련된 함수로 cons와 car과 cdr(could-er라 읽는다)가 있다. cons는 list를 만들고, car은 list의 첫번째 element를 리턴하고, cdr은 list의 첫번째를 제외한 나머지를 리턴한다. (cons 'a '()) => (a) (car '(a b c)) => a (cdr '(a b c)) => (b c) cons는 pair를 가지고 list를 만든다. 이때 꼭 두번째 파라메터가 list일 필요는 없다. 이렇게 두번째 파라메터가 list가 아닐 경우를 improper list라 부르고 dotted-pair notation으로 표시한다. (cons 'a 'b) => (a . b) (cdr '(a . b)) => b 변수에 값을 주고 싶은 경우 let를 사용한다. 형태는 (let ((var expr) ...) body1 body2 ...) 이다. var은 body에서만 유효하다. var을 정의할 때 ()대신 [] 사용할 수 있다. (let ((x 2)) (+ x 3)) => 5 (let ([x 2]) (+ x 3)) => 5 procedure의 선언을 위해 lanbda를 사용한다. 형식은 (lambda (var ...) body1 body2 ...)이다. (lambda (x) (+ x x)) => #((lambda (x) (+ x x)) (* 3 4)) => 24 아래와 같이 procedure를 정의할 때 lambda에 관계되지 않는 variable을 쓰면 어떻게 될까? (let ([f (let ([x 'sam]) (lambda (y z) (list x y z)))]) (f 'i 'am)) => (sam i am) 결과를 보면 알 수 있듯이 lambda를 정의할 때의 x값인 sam이 proedure에 들어가 있게 된다.(이것을 static scoping이라 한다.) 따라서 아래처럼 해도 결과는 똑같게 나온다. (let ([f (let ([x 'sam]) (lambda (y z) (list x y z)))]) (let ([x 'not-sam]) (f 'i 'am)) => (sam i am) 실제로 lambda의 형식은 세 종류로 이야기할 수 있다. 1. parameter의 개수가 정해져 있는 경우(앞에서 이야기한) 2. 하나의 variable만 오는 경우(괄호가 없는것에 주의) 이 variable에 argument의 list가 들어간다. ;; x에 1 2 3 4가 list인 (1 2 3 4)를 가지게 된다. (let ([f (lambda x x)]) (f 1 2 3 4)) => (1 2 3 4) 3. 정해진 variable이후 하나의 variable이 오고 이 variable에 나머지 argument가 list로 들어가는 경우 ;; x에는 a가, y에는 b가, z에는 c와d의 list인 (c d)가 들어가게 된다. (let ([h (lambda (x y . z) (list x y z))]) (h 'a 'b 'c 'd)) => (a b (c d)) let이나 lambda에 의한 expression은 특정 영역에서만 유효하게 된다. primitive procedure처럼 쓰는 경우를 원한다면 define를 쓴다. (define double-any (lambda (f x) (f x x))) ;; 한번 double-any를 위와 같이 정의하고 나면 어디서든 사용할 수 있다. (double-any + 10) => 20 lambda를 이용한 define의 경우 (define (var0 var1 ... varn) e1 e2 ...)의 형태로 간단하게 쓸 수 있다. (define (cadr x) (car (cdr x))) 조건문의 경우 (if test consequent alternative)로 쓴다. (define abs (lambda (n) (if (< n 0) (- 0 n) n))) (abs 77) => 77 (abs -77) => 77 or은 (or expr ...)이다. expr을 순서대로 계산한 후 true가 있으면 true이고 없으면 false이다. and는 (and expr ...)이다. expr을 순서대로 계산하다가 false가 있으면 false이고 모두가 true이면 true이다. and와 or 둘다 마지막으로 계산한 expression의 값을 리턴한다. predicate의 경우 ?(question mark)를 주로 끝에 붙여준다. null?은 null을 체크한다. (null? '()) => #t (null? 'abc) => #f eqv?는 두 argument가 같은지를 비교한다. (eqv? 'a 'a) => #t (eqv? 'a 'b) => #f (eqv? (cons 'a 'b) (cons 'a 'b)) => #f ;; 다른 cons에 의해 생성되었기 때문에 false이다. object의 type을 비교하는 함수로 pair?, symbol?, number?, string?등이 있다. 조건문이 중첩되거난 하는 경우는 cond를 사용하는 것이 편할 수 있다. cond의 형태는 (cond (test expr) ... (else expr))이다. else는 적용되는 값이 없을 경우 실행된다. else는 생략할 수 있다. (define sign (lambda (n) (cond [(< n 0) -1] [(> n 0) +1] [(= n 0) 0]))) list의 길이를 계산하는 함수는 아래와 같이 만들 수 있다. (define length (lambda (ls) (if (null? ls) 0 (+ (length (cdr ls)) 1)))) 위처럼 base case와 recursion step을 갖는 것을 recursion이라 부른다. assignment는 set!으로 할 수 있다. (define abcde '(a b c d e)) abcde => (a b c d e) (set! abcde (cdr abcde)) abcde => (b c d e)
Thursday, August 25, 2011
Chapter 2. Getting Started
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment