clisp chapter4
1. True/False
다음과 같이 4가지 경우를 Lisp에서는 False로 본다.
'(), (), 'nil, nil
이 이외의 것은 모두 True이다.
item이 있는 list는 참이다.
> (if '()
'i-am-true
'i-am-false)
I-AM-FALSE
</p>
> (if '(1)
'i-am-true
'i-am-false)
I-AM-TRUE
> (eq '() nil)
T
> (eq '() ())
T
> (eq '() 'nil)
T
두번 째는 빈 리스트를 해석할 때는 자연스럽게 저렇게 처리된다.
세번 째는 lisp에서 nil과 빈괄호는 동일한 것으로 처리하기 때문이다.
2. if(조건문)
> (if (= (+ 1 2) 3)
'yup
'nope)
YUP
> (if (= (+ 1 2) 4)
'yup
'nope)
NOPE
> (if '(1)
'the-list-has-stuff-in-it
'the-list-is-empty)
THE-LIST-HAS-STUFF-IN-IT
> (if '()
'the-list-has-stuff-in-it
'the-list-is-empty)
THE-LIST-IS-EMPTY
> (if (oddp 5)
'odd-number
(/ 1 0))
ODD-NUMBER
> (defvar *number-was-odd* nil)
*NUMBER-WAS-ODD*
> (if (oddp 5)
(progn (setf *number-was-odd* t)
'odd-number)
'even-number)
ODD-NUMBER
2.1 when
> (when (oddp 5)
(setf *number-is-odd* t)
'odd-number)
ODD-NUMBER
> *number-is-odd*
T
2.2 unless
> (unless (oddp 4)
(setf *number-is-odd* nil)
'even-number)
EVEN-NUMBER
> *number-is-odd*
T
2.3 cond
> (defvar *arch-enemy* nil)
*ARCH-ENEMY*
> (defun pudding-eater (person)
(cond ((eq person 'henry) (setf *arch-enemy* 'lisp-alien)
'(curse you lisp alien ? you ate my pudding))
((eq person 'johnny) (setf *arch-enemy* 'johnny)
'(i hope you choked on my pudding johnny))
(t '(why you eat my pudding strange ?))))
PUDDING-EATER
> (pudding-eater 'johnny)
(I HOPE YOU CHOKED ON MY PUDDING JOHNNY)
> *arch-enemy*
JOHNNY
>(pudding-eater 'test)
(WHY YOU EAT MY PUDDING STRANGER ?)
위의 예제에서는 henry, johnny, 그리고 나머지 경우(t)로 구분하였다.
cond는 위에서부터 차례대로 조건을 비교한다. 마지막 구문에 참 조건(t)가 있어, 두 가지 조건을 다 만족하지 못 하였을 경우 세 번째 조건이 무조건 실행되도록 하였다.
2.4 case</h4>
case는 cond보다 조금 더 간결하다.
> (defun pudding-eater (person)
(case person
((henry) (setf *arch-enemy* 'stupid-lisp-alien)
'(curse you lisp alien ? you ate my pudding))
((johnny) (setf *arch-enemy* 'useless-old-johnny)
'(I hope you choked on my pudding johnny))
(otherwise '(why you eat my pudding stranger ?))))
PUDDING-EATER
> (pudding-eater 'johnny)
(I HOPE YOU CHOKED ON MY PUDDING JOHNNY)
> (pudding-eater 'henry)
(CURSE YOU LISP ALIEN ? YOU ATE MY PUDDING)
주의) case는 비교할 때 내부적으로 eq를 쓴다. 심볼 값으로 분기할 경우에만 사용한다.
</p>
3. and/or
> (defun pudding-eater (person)
(case person
((henry) (setf *arch-enemy* 'stupid-lisp-alien)
'(curse you lisp alien ? you ate my pudding))
((johnny) (setf *arch-enemy* 'useless-old-johnny)
'(I hope you choked on my pudding johnny))
(otherwise '(why you eat my pudding stranger ?))))
PUDDING-EATER
> (pudding-eater 'johnny)
(I HOPE YOU CHOKED ON MY PUDDING JOHNNY)
> (pudding-eater 'henry)
(CURSE YOU LISP ALIEN ? YOU ATE MY PUDDING)
and와 or는 간단한 수학 연산자이고 불린 값을 만들어낸다.
기본적으로 다음과 같이 사용할 수 있다.
> (and (oddp 5) (oddp 7) (oddp 9))
T
> (or (oddp 4) (oddp 7) (oddp 8))
T
(boolean short circuit evaluation을 통해서 다음과 같이 적용된다.)<br>
> (or (oddp 4) (setf *is-it-even* t))
T
> *is-it-even*
T
> (if (member 1 '(3 4 1 5))
'one-is-in-the-list
'one-is-not-in-the-list)
ONE-IS-IN-THE-LIST
> (member 1 '(3 4 1 5))
(1 5)
4. 비교함수
비교함수는 다음과 같이 다양하게 있다.
eq, eql, equal, =, string-equal, equalp
저자는 심볼을 비교할 때에는 eq, 다른 것을 비교할 때에는 equal을 권유한다.
비교함수들 중 eq을 가장 간단하고 빠르다. 따라서 심볼을 사용할 때에는 eq을 사용하는 것을 권장한다.
> (defparameter *fruit* 'apple)
FRUIT
> (cond ((eq *fruit* 'apple) 'its-an-apple)
((eq *fruit* 'orange) 'its-an-orange))
ITS-AN-APPLE
equal은 두 심볼이 같은 데이터를 가지고 있는지 판단한다.
> (equal 'apple 'apple)
T
> (equal (list 1 2 3) (list 1 2 3))
T
> (equal '(1 2 3) (cons 1 (cons 2 (cons 3 ()))))
T
> (eql 'foo 'foo)
T
> (eql 3.4 3.4)
T
문자열 비교에서는 대소문자 구분없이 비교하고, 숫자에서는 정수와 소수를 비교할 수도 있다.
> (equalp "Bob Smith" "bob smith")
T
> (equalp 3.0 3)
T