2008. 9. 16.
PCL Ch3. save-db load-db 변경하기
환경은 CLISP + emacs + slime
CLISP은 유니코드를 지원한다. 유니코드를 지원하게 하기위해서는
라인을 .emacs 에 넣어두어야한다.
우선 여기까지 되었으면 with-open-file 에서 각 stream에 encoding을 정의해주어야한다.
몇가지 예제 파일을 찾다가 Common Lisp Cookbook 에서 힌트를 찾았다.
:external-format을 설정해주면 모든 문제가 일단 OK
아래는 변경한 save-db, load-db이다.
이상으로 문제는 완료..
이제 유니코드를 사용해도 정상적으로 출력이 된다. 핵심은 역시 (ext: ... ) 부분..

CLISP은 유니코드를 지원한다. 유니코드를 지원하게 하기위해서는
<blockquote>(setq slime-net-coding-system 'utf-8-unix)</blockquote>
라인을 .emacs 에 넣어두어야한다.
우선 여기까지 되었으면 with-open-file 에서 각 stream에 encoding을 정의해주어야한다.
몇가지 예제 파일을 찾다가 Common Lisp Cookbook 에서 힌트를 찾았다.
:external-format을 설정해주면 모든 문제가 일단 OK
아래는 변경한 save-db, load-db이다.
(defun save-db (filename)
(with-open-file (out filename
:external-format (ext:make-encoding :charset 'charset:utf-8 :line-terminator :unix)
:direction :output
:if-exists :supersede)
(with-standard-io-syntax (print *db* out))))
(defun load-db (filename)
(with-open-file (in filename
:external-format (ext:make-encoding :charset 'charset:utf-8 :line-terminator :unix))
(with-standard-io-syntax
(setf *db* (read in)))))
이상으로 문제는 완료..
이제 유니코드를 사용해도 정상적으로 출력이 된다. 핵심은 역시 (ext: ... ) 부분..

2008. 9. 9.
PCL ch4.함수의 정의
* 함수 정의하는 형태
* 파라미터 리스트 : 함수에 전달되는 인자를 받을 변수를 정의한다.
- 필수 파라미터 : 변수 이름의 리스트
- 옵션 파라미터
옵션 파라미터에 디폴트 값을 넣고 싶다면 다음과 같이 사용한다.
만약 주어진 옵션 파라미터에 값이 등록되었는지를 알고 싶다면 "-supplied-p" 변수를 이용할 수 있다. 해당하는 변수가 등록되었다면 T, 그렇지 않다면 NIL 이다.
- Keyword 파라미터 : 어떤 인수가 어떤 변수로 매핑될지 일일이 정하고 싶다면 사용한다. 또한 &optional 에서 처럼 기본값과 등록되었는지 확인하는 변수 모두 사용이 가능하다.
* Return 값 강제하기
- RETURN-FROM, BLOCK
BLOCK으로 해당 블록의 이름을 정한 후 RETURN-FROM을 이용해 해당 블록에서 탈출한다. 기본적으로 함수정의안에서는 함수 이름자체가 하나의 블록으로 취급된다.
- LAMBDA, FUNCALL, APPLY
일반적으로 함수를 사용한다는 것은 다음과 같다.
apply는 funcall과 유사하지만 개별 인자들을 일일이 가져오는 형식이 아니고, 리스트 자체를 받아오는 경우에 사용한다.
lambda는 이름없는 함수를 만들 수 있다.

<blockquote>(defun name (parameters)
"Optional document string"
bodyform)
</blockquote>
* 파라미터 리스트 : 함수에 전달되는 인자를 받을 변수를 정의한다.
- 필수 파라미터 : 변수 이름의 리스트
- 옵션 파라미터
<blockquote>(defun foo (a b &optional c) ... )<br /></blockquote>
- a, b 두 인자는 필수 파라미터이다. 따라서 먼저 두 변수에 값이 할당된다.
- 이후에도 남은 값이 있다면 그때 c에 할당된다.
옵션 파라미터에 디폴트 값을 넣고 싶다면 다음과 같이 사용한다.
<blockquote>(defun foo (a b &optional (c 10)) ... )</blockquote>
만약 주어진 옵션 파라미터에 값이 등록되었는지를 알고 싶다면 "-supplied-p" 변수를 이용할 수 있다. 해당하는 변수가 등록되었다면 T, 그렇지 않다면 NIL 이다.
<blockquote>(defun foo (a b &optional (c 0 c-supplied-p)) <br /> (list a b c c-supplied-p))</blockquote>- Rest 파라미터 : 여러 개의 인수를 받고자할 때 사용한다.
<blockquote>(defun foo (a b &rest c) ... )</blockquote>
- Keyword 파라미터 : 어떤 인수가 어떤 변수로 매핑될지 일일이 정하고 싶다면 사용한다. 또한 &optional 에서 처럼 기본값과 등록되었는지 확인하는 변수 모두 사용이 가능하다.
<blockquote>(defun foo (&keyword a b (c 0) (d 0 d-supplied-p)) (list a b c d d-supplied-p)) </blockquote>해당하는 값을 등록하고 싶다면 :a :b 식으로 :을 변수명 앞에 붙여 값을 가져올 수 있다.
* Return 값 강제하기
- RETURN-FROM, BLOCK
BLOCK으로 해당 블록의 이름을 정한 후 RETURN-FROM을 이용해 해당 블록에서 탈출한다. 기본적으로 함수정의안에서는 함수 이름자체가 하나의 블록으로 취급된다.
<blockquote>(defun foo (n)<br /> (dotimes (i 10)<br /> (dotimes (j 10)<br /> (when (> (* i j) n)<br /> (return-from foo (list i j))))))</blockquote>* 고차 함수 (Higher-order function)
- LAMBDA, FUNCALL, APPLY
일반적으로 함수를 사용한다는 것은 다음과 같다.
<blockquote>(foo 1 2 3) == (funcall #'foo 1 2 3) </blockquote>이때 #'는 해당하는 함수를 찾아오는 함수이다. 일종의 함수 포인터 연산이라고 생각해도 되겠다. (Scheme과는 달리 LISP은 변수공간과 함수 공간이 구분되어있다.)
apply는 funcall과 유사하지만 개별 인자들을 일일이 가져오는 형식이 아니고, 리스트 자체를 받아오는 경우에 사용한다.
lambda는 이름없는 함수를 만들 수 있다.
<blockquote>(funcall #'(lambda (x y) (+ x y)) 3 5) ==> 8</blockquote>

2008. 9. 2.
연습문제 4.6
(define (let? exp)
(tagged-list? exp 'let))
(define (let-body exp)
(caddr exp))
(define (let-vars exp)
(let ((var-exp-list (cadr exp)))
(map car var-exp-list)))
(define (let-exps exp)
(let ((var-exp-list (cadr exp)))
(map cadr var-exp-list)))
(define (let->combination exp)
(cons
(make-lambda (let-vars exp)
(let-body exp))
(let-exps exp)))

연습문제 4.4
<blockquote>(define (eval-and exp env)
(if (null? exp)
#t
(let ((test (car exp)))
(if (eval test)
(eval-and (cdr exp) env)
#f))))
(define (eval-or exp env)
(if (null? exp)
#f
(let ((test (car exp)))
(if (eval test)
#t
(eval-or (cdr exp) env)))))
(define (and? exp)
(tagged-list? exp 'and))
(define (or? exp)
(tagged-list? exp 'or))
</blockquote>
좀 아리까리함..

연습문제 4.3
(define eval-table (make-table))
(define get (eval-table 'lookup-proc))
(define put (eval-table 'insert-proc!))
(define (eval-quoted exp env)
(text-of-quotation exp))
(define (eval-set exp env)
(eval-assignment exp env))
(define (eval-define exp env)
(eval-definition exp env))
(define (eval-if. exp env)
(eval-if exp env))
(define (eval-lambda exp env)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
(define (eval-begin exp env)
(eval-sequence (begin-actions exp) env))
(define (eval-cond exp env)
(eval (cond->if exp) env))
(put 'quote eval-quoted)
(put 'set eval-set)
(put 'define eval-definition)
(put 'if eval-if.)
(put 'lambda eval-lambda)
(put 'begin eval-begin)
(put 'cond eval-cond)
(define (eval exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
((get (car exp))
((get (car exp)) exp env))
((application? exp)
(apply (eval (operator exp) env)
(list-of-values (operands exp) evn)))
(else
(error "Unknown expression type -- EVAL" exp))))

연습문제 4.2
a. 프로시저 적용이 우선되게될 때 (define x 3)를 예로 들어 보자.
이 경우 eval은 (define x 3)를 define 정의 식이 아니라, 일반 프로시저로 인식하게 된다.
따라서 define이라는 프로시저에 (x 3) 을 넣어 해당하는 결과를 수행하도록 식을 평가하게된다. 따라서, application이 무리하게 먼저 실행되면 심각한 문제가 발생하게된다.
b. 굳이 application을 call을 사용해서 수행하고 싶다면 다음과 같이 변경한다.

이 경우 eval은 (define x 3)를 define 정의 식이 아니라, 일반 프로시저로 인식하게 된다.
따라서 define이라는 프로시저에 (x 3) 을 넣어 해당하는 결과를 수행하도록 식을 평가하게된다. 따라서, application이 무리하게 먼저 실행되면 심각한 문제가 발생하게된다.
b. 굳이 application을 call을 사용해서 수행하고 싶다면 다음과 같이 변경한다.
<blockquote>
(define (application? exp) (tagged-list? exp 'call))
(define (operator exp) (cadr exp))
(define (operands exp) (cddr exp))</blockquote>

연습문제 4.1
(define (list-of-values exps env)
(if (no-operands? exps)
'()
(let ((left-values (eval (first-operands exps))))
(let ((right-values (list-of-values (rest-operands exps))))
(cons left-values right-values)))))
오른쪽부터 셈하도록 하려면 left-values와 right-values의 위치를 바꿔주면 된다.

피드 구독하기:
글 (Atom)