Определение собственного макроса для проверки условия - Lisp

Узнай цену своей работы

Формулировка задачи:

Здравствуйте. Помогите пожалуйста с написанием макроса на LISP. Определить макрос our-if, который имеет следующую форму
(OUR-IF test :THEN exp1 exp2… :ELSE exp3 exp4 …)
Макрос производит следующие действия:
> (our-if (> 3 1) :then ‘ok)    
OK
> (our-if (< 5 3) :else ‘ok)
OK
> (our-if (> 3 1) :else ‘oops)
NIL
> (our-if (> 3 1) :then)
NIL
> (our-if (> 3 1) :else ‘oops :then ‘ok)
ok  
> (our-if (> 3 1) :then ‘ok :else ‘oops)
ok
Дело в том, что я видела похожее задание с решением на этом форуме, однако оно не подходит для данных действий) Я попыталась переделать что то сама:
(defmacro our-if (test &rest body)
  (let* ((bt (position :then body))
         (et (position :else body))
         (th (cdr (member :then body)))
         (el (cdr (member :else body))))
    `(cond
       (,test, nil ,@th)
       (t ,@el))))
И оно даже выдает то что нужно почти для всех случаев, кроме последнего, но я точно знаю что данный макрос не верен и работает некорректно. А как переделать, ума не приложу. буду благодарна за помощь!)

Решение задачи: «Определение собственного макроса для проверки условия»

textual
Листинг программы
(defmacro our-if (&body body)
  (destructuring-bind (test-form &optional body-clause)
      (split-sequence :then body)
    (when body-clause
      (destructuring-bind (then-form &optional else-form)
          (split-sequence :else body-clause)
        `(if (progn ,@test-form)
             (progn ,@then-form)
             (progn ,@else-form))))))
 
 
(macroexpand '(our-if 1))
;; NIL
;; T
 
 
(macroexpand '(our-if 1 :then (foo) (bar)))
;; (IF (PROGN 1)
;;     (PROGN (FOO) (BAR))
;;     (PROGN))
;; T
 
(macroexpand '(our-if 1 :then (foo) (bar) :else (baz)))
;; (IF (PROGN 1)
;;     (PROGN (FOO) (BAR))
;;     (PROGN (BAZ)))
;; T

Объяснение кода листинга программы

В этом коде определён макрос с именем our-if. Этот макрос принимает произвольное количество аргументов, которые могут быть либо одним выражением, либо последовательностью выражений, заключённых в begin и разделённых запятыми. Аргументы, которые являются последовательностью выражений, разделённых запятыми, заключены в split-sequence. Это выражение либо помещается в then-form, либо в else-form в зависимости от того, есть ли у аргумента заголовок :then. В этом макросе используется вспомогательный макрос split-sequence, который принимает два аргумента: последовательность для разбиения и заголовок, который определяет, где поместить результат разбиения. Если заголовок :then, то результат помещается в then-form, если :else, то в else-form. Синтаксис этого макроса напоминает синтаксис встроенного макроса if, за исключением того, что вместо then-form и else-form используется test-form, then-clause и else-clause. Когда макрос our-if вызывается с аргументом :then и без :else, результат будет nil, потому что он ожидает два аргумента после :then. Когда макрос our-if вызывается с аргументами :then и :else, и без аргументов, результат будет nil, потому что он ожидает по крайней мере один аргумент после каждого из ключевых слов :then и :else. Когда макрос our-if вызывается с аргументами :then и :else, и с аргументами после каждого из ключевых слов :then и :else, результат будет nil, потому что он ожидает еще одного аргумента после каждого из ключевых слов :then и :else. Когда макрос our-if вызывается с аргументами :then и :else, и с аргументами после каждого из ключевых слов :then и :else, и без аргументов, результат будет nil, потому что он ожидает по крайней мере одного аргумента после каждого из ключевых слов :then и :else.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

6   голосов , оценка 4 из 5
Похожие ответы