조건 쓰기

질문에 맞춰 if, cond, case를 고르고 어떤 식이 실행되는지 확인합니다.

조건식 고르기

예·아니오 질문 하나에는 if를, 여러 조건에는 cond를, 한 값과 고정 데이터의 비교에는 case를 쓰세요. 이 페이지에서 각 형식이 어떤 식을 평가하는지 확인할 수 있습니다. cond와 case처럼 다른 형식으로 풀려 실행되는 문법을 파생 형식이라고 부릅니다.

실행으로 확인하기

LISPEX
(case 2 ((1) 'one) ((2) 'two) (else 'other))

관측 결과

출력
two

case는 2를 한 번 평가하고 두 번째 절을 고릅니다. 다른 절의 본문은 평가하지 않고 심볼 two를 반환합니다.

LISPEX
(if #t 42 (/ 1 0))
(cond ((< 3 0) (/ 1 0))
      ((< 3 5) 'small)
      (else 'large))

관측 결과

42
small

if는 조건을 평가한 뒤 선택한 분기만 평가합니다. cond는 조건을 차례로 검사하고 처음 참인 절의 본문을 실행합니다. 그 뒤의 절은 조건 검사도 건너뜁니다. 위 예제에서 나눗셈은 둘 다 실행되지 않습니다.

각 코드 블록을 플레이그라운드에서 실행해 보세요. 위 결과처럼 값이 한 줄씩 나옵니다.

형식 읽기

형식은 (if #t 1 0)처럼 프로그램을 이루는 문법 단위입니다. datum은 수나 심볼, 리스트처럼 하나로 읽는 데이터입니다. case는 각 절의 데이터를 비교할 값과 eqv?로 비교합니다. 이 데이터를 식으로 평가하지 않습니다.

거짓인 값은 #f뿐입니다. 다른 값은 모두 참으로 취급합니다.

형식쓸 때결과 동작
if조건 하나로 두 분기 중 하나를 고를 때선택한 분기가 낸 값들을 반환
cond여러 조건으로 경우를 나눌 때처음 맞는 절이 낸 값들을 반환
case한 값을 고정 데이터와 비교할 때비교할 값을 한 번 평가하고 맞는 절을 실행
and / or앞선 결과에 따라 다음 검사를 결정할 때처음 거짓인 값 / 참인 값에서 멈추고 피연산자 값을 반환
when / unless한쪽 경우에만 본문을 실행할 때본문을 건너뛰면 값 0개를 반환

and와 or는 결과가 정해지면 나머지 식을 평가하지 않습니다. 이를 단락 평가라고 합니다. 결과를 불리언으로 바꾸지 않고 피연산자 값을 그대로 반환합니다.

조건에 따라 본문 실행하기

when은 조건이 참일 때 본문을 차례로 실행합니다. unless는 조건이 거짓일 때 본문을 실행합니다. 둘 다 본문의 마지막 식이 낸 결과를 반환합니다.

(when #t 42)는 42를, (unless #f 7)은 7을 반환합니다. 본문을 건너뛰면 값을 하나도 내지 않습니다. when은 조건이 #f일 때, unless는 조건이 참일 때 본문을 건너뜁니다.

잡을 수 있는 오류는 (guard (변수 절 ...) 본문 ...)으로 처리합니다. guard는 잡은 객체를 변수에 묶고 cond처럼 절을 차례로 검사합니다. 마지막 else 절로 나머지 경우를 처리할 수 있습니다. 맞는 절이 없으면 원래 오류를 다시 발생시킵니다.

실행 전에 문법 확인하기

  • if에는 조건과 두 분기가 모두 필요합니다. (if #t 1)은 거짓 분기가 없어서 E130이 납니다.
  • cond나 case에서 맞는 절도 else도 없으면 값 0개를 반환합니다. 그 결과를 값 하나가 필요한 자리에 쓰면 E320이 납니다.
  • else는 cond와 case, guard의 절 머리에서 특별한 뜻을 가집니다. 예약어는 아니므로 (define else 5)도 쓸 수 있습니다.
  • cond에 => 화살표 절을 쓰면 E130이 납니다. case 절의 본문에서 =>는 일반 이름입니다. 이 이름을 정의하지 않고 평가하면 E300이 납니다.
  • 준인용 밖에 쓴 unquote와 unquote-splicing은 실행 전에 발견하는 정적 오류입니다.

분기를 건너뛴다는 것은 그 분기를 평가하지 않는다는 뜻입니다. 리스펙스는 실행 전에 프로그램 전체의 문법을 검사합니다.

축약 문법이 실행되는 방식

리스펙스는 실행 전에 축약 문법을 핵심 형식으로 바꿉니다. 이 단계를 정규화라고 합니다. cond와 case, and, or, when, unless, let*, 이름 있는 let, do, 준인용의 변환 규칙은 내장되어 있습니다.

정규화는 평가 순서와 꼬리 위치를 보존합니다. 꼬리 위치는 현재 호출에서 더 할 일 없이 식의 결과를 바로 반환하는 자리입니다. 정규화가 만든 이름은 사용자 이름과 충돌하지 않으며, 사용자가 정의한 이름으로 숨은 내장 연산을 바꿀 수도 없습니다.

리스펙스는 내장 규칙에 따라 문법을 변환합니다. define-syntax와 사용자 정의 매크로는 거부합니다.

다음으로

데이터와 결정에서 조건식 고르기를 연습하세요. 축약 문법을 바꾸는 방식은 기본 형식으로 풀리는 문법에서 확인할 수 있습니다.