На этом шаге мы рассмотрим задачи, расширяющие возможности учебного интерпретатора языка LISP.
1. <-- ((NLAMBDA1 (X) (CDR1 X)) (1 (TIMES1 1 2) 4)) --> ((TIMES1 1 2) 4) <-- ((NLAMBDA1 (X) (CAR1 X)) ((TIMES1 1 2) (PLUS1 1 4))) --> (TIMES 1 2) 2. <-- (DEFUN1 SUMMA (LAMBDA1 (LST) (COND1 ((EQUAL1 LST NIL1) 0) (T1 (PLUS1 (CAR1 LST) (SUMMA (CDR1 LST)))))) --> (LAMBDA1 (LST) (COND1 ((EQUAL1 LST NIL1) 0) (T1 (PLUS1 (CAR1 LST) (SUMMA (CDR1 LST))))) <-- (SUMMA (QUOTE1 (1 2 3))) --> 6 3. <-- (DEFUN1 FACT (LAMBDA1 (X) (COND1 ((EQUAL1 X 1) 1) (T1 (TIMES1 X (FACT (DIFFERENCE1 X 1))))))) --> (LAMBDA1 (X) (COND1 ((EQUAL1 X 1) 1) (T1 (TIMES1 X (FACT (DIFFERENCE1 X 1)))))) <-- (FACT 5) --> 120 4. <-- (DEFUN1 TEST (LAMBDA1 (X Y) (CONS1 X Y))) --> (LAMBDA1 (X Y) (CONS1 X Y)) <-- (TEST A B) --> (A . B) 5. <-- (DEFUN1 COPY (LAMBDA1 (E) (COND1 ((ATOM1 E) E) (T (CONS1 (COPY (CAR1 E)) (COPY (CDR1 E))))))) --> (LAMBDA1 (E) (COND1 ((ATOM1 E) E) (T (CONS1 (COPY (CAR1 E)) (COPY (CDR1 E)))))) <-- (COPY (QUOTE1 (A B C))) --> (A B C) 6. <-- (DEFMACRO1 AAA (NLAMBDA1 (G) (CAR1 G))) --> (NLAMBDA1 (G) (CAR1 G)) <-- (AAA ((TIMES1 2 3) 4 5)) --> (TIMES1 2 3)
Далее можно все более и более расширять возможности построенного интерпретатора, пользуясь собственным механизмом определения функций.
Например, определим функцию NULL1 через примитивы системы:
<-- (DEFUN1 NULL1 (LAMBDA1 (L) (EQUAL1 L NIL1))) --> (LAMBDA1 (L) (EQUAL1 L NIL1))
7. <-- (DEFUN1 MEMBER1 (LAMBDA1 (AL LST) (COND1 ((NULL1 LST) NIL1) ((EQUAL1 AL (CAR1 LST)) LST) (T1 (MEMBER1 AL (CDR1 LST)))))) --> (LAMBDA1 (AL LST) (COND1 ((NULL1 LST) NIL1) ((EQUAL1 AL (CAR1 LST)) LST) (T1 (MEMBER1 AL (CDR1 LST))))) <-- (MEMBER1 (QUOTE1 B) (QUOTE1 (A B C))) --> (B C) 8. <-- (DEFUN1 DEL (LAMBDA1 (A L) (COND1 ((NULL1 L) NIL1) ((EQUAL1 (CAR1 L) A) (CDR1 L)) (T1 (CONS1 (CAR1 L) (DEL A (CDR1 L))))))) --> (LAMBDA1 (A L) (COND1 ((NULL1 L) NIL1) ((EQUAL1 (CAR1 L) A) (CDR1 L)) (T1 (CONS1 (CAR1 L) (DEL A (CDR1 L))))) <-- (DEL 5 (QUOTE1 (3 4 5))) --> (3 4) 9. <-- (DEFUN1 EVERY (LAMBDA1 (L) (COND1 ((NULL1 L) NIL1) ((NULL1 (CDR1 L)) L) (T1 (CONS1 (CAR1 L) (EVERY (CDR1 (CDR1 L)))))))) --> (LAMBDA1 (L) (COND1 ((NULL1 L) NIL1) ((NULL1 (CDR1 L)) L) (T1 (CONS1 (CAR1 L) (EVERY (CDR1 (CDR1 L))))))) <-- (EVERY (QUOTE1 (A P R O L D))) (A R L) 10. <-- (DEFUN1 APPEND1 (LAMBDA1 (L1 L2) (COND1 ((NULL1 L1) L2) ( T1 (CONS1 (CAR1 L1) (APPEND1 (CDR1 L1) L2))))))) --> (LAMBDA1 (L1 L2) (COND1 ((NULL1 L1) L2) ( T1 (CONS1 (CAR1 L1) (APPEND1 (CDR1 L1) L2)))))) <-- (APPEND1 (QUOTE1 (A P R)) (QUOTE1 (O L D))) (A P R O L D)
(A (B1 B2 ... BN)) --> ((A B1) (A B2) ... (A BN))
((A1 A2 ... AN) B) --> ((A1 B) (A2 B) ... (AN B));
При вычислении предиката ALL выражение E вычисляется дважды, сначала переменная T получает значение T, а затем NIL. К результатам применяется операция AND. Аналогично предикат EXIST также требует вычисления выражения E при двух различных значениях переменной. К результатам применяется затем операция OR. Такой интерпретатор является вычислительной формой пропозиционального исчисления.
Со следующего шага мы начнем приводить задачи с решениями.