값을 바꾸고 프로시저를 호출하는 순서를 따라가면 프로그램의 결과를 예측할 수 있습니다. 리스펙스는 호출의 연산자를 먼저 평가하고 피연산자를 왼쪽부터 평가합니다.
바뀌는 값 따라가기
아래 프로그램 전체를 플레이그라운드에 붙여 넣으세요.
(define x 0)
(list (begin (set! x 1) x) (begin (set! x (+ x 1)) x))결과
(1 2)첫 begin은 x를 1로 바꾸고 1을 돌려줍니다. 두 번째는 새 값을 읽어 1을 더하고 2를 저장한 뒤 돌려줍니다. list 프로시저는 1과 2를 차례로 받습니다.
호출에서 연산자는 프로시저를 구하는 식입니다. 이 예제에서는 list입니다. 피연산자는 인자로 전달할 값을 구하는 식이며, 여기서는 두 begin 식입니다.
식마다 순서 확인하기
| 식 | 평가 순서 | 결과 처리 |
|---|---|---|
| 프로시저 호출 | 연산자, 그다음 피연산자를 왼쪽부터 | 인자 수를 검사한 뒤 프로시저를 호출합니다 |
begin이나 프로시저 본문 | 식을 왼쪽부터 | 앞선 결과는 버리고 마지막 결과를 돌려줍니다 |
if | 검사식, 그다음 선택한 분기 | 선택한 분기의 결과를 돌려줍니다 |
and | 피연산자를 왼쪽부터 | #f에서 멈추거나 마지막 결과를 돌려줍니다 |
or | 피연산자를 왼쪽부터 | #f가 아닌 첫 결과에서 멈춥니다 |
let | 바깥 스코프의 이름으로 초기식을 왼쪽부터 | 본문에서 쓸 새 이름에 값을 연결합니다 |
let* | 초기식 하나를 평가한 뒤 이름에 값을 연결 | 뒤의 초기식은 앞서 만든 이름을 쓸 수 있습니다 |
letrec | 모든 이름의 저장 공간을 만든 뒤 초기식을 왼쪽부터 평가하고 저장 | 초기화 중에 모든 이름을 볼 수 있습니다 |
초기식은 이름에 처음 연결할 값을 구합니다. 스코프는 이름을 볼 수 있는 범위입니다. 이름 하나의 값을 저장하는 공간을 셀이라고 합니다. 값이 아직 없는 letrec 셀을 읽으면 E321이 납니다.
오류가 나면 현재 평가를 멈춥니다. 위 순서는 오류가 나기 전까지 도달한 식에 적용됩니다. begin이나 본문의 마지막 식 앞에서는 결과를 버리므로 값이 몇 개 나와도 됩니다.
건너뛰는 식 확인하기
아래 코드를 별도 프로그램으로 실행하세요.
(list (if #t 7 (/ 1 0))
(and #f (/ 1 0))
(or 0 (/ 1 0)))결과
(7 #f 0)나눗셈은 하나도 실행하지 않습니다. if는 7을 선택하고, and는 #f에서, or는 0에서 멈춥니다. 거짓은 #f뿐이므로 0은 참으로 다룹니다.
평가한 뒤 인자 수 검사하기
인자 수가 맞지 않아도 연산자와 피연산자는 먼저 실행됩니다. 네이티브 CLI를 설치한 뒤 아래 전체 내용을 arity-effects.lspx로 저장하세요.
((begin (display "operator ") (lambda (x) x))
(begin (display "left ") 1)
(begin (display "right") 2))lispex run arity-effects.lspx표준 출력에는 다음 텍스트가 나오며 끝에 줄바꿈은 없습니다.
operator left right프로시저가 받는 인자는 하나인데 두 개를 전달했습니다. 명령은 이어서 표준 오류에 다음 진단을 씁니다.
E302 arity-effects.lspx:1:1 arity mismatch: expected 1 argument(s), got 2종료 코드는 1이고 새 파일은 만들지 않습니다. 프로시저 본문은 실행하지 않습니다.