Макрос цепочек функций Lisp - PullRequest
4 голосов
/ 29 января 2010

Есть ли готовый макрос для lisp, который позволяет объединять функции в цепочку? Я не мог найти один. Я попытаюсь объяснить, что я имею в виду с этим примером.

Вместо использования let * с большим количеством неиспользуемых промежуточных переменных, таких как:

(let*
  ((var1 (f1 x y))
   (var2 (f2 x var1))
   (var3 (f1 var2 z)))
 var3)

Мне бы хотелось, чтобы это было написано так:

(->
  (f1 x y)
  (f2 x _)
  (f1 _ z))

где, очевидно, _ будет возвращаемым значением из предыдущего выражения. Плюсом является возможность использования _1 , _2 , ... для ссылки на ранее возвращенные значения.

Это идея, точный синтаксис не так важен.

Я знаю, что это не так сложно написать, но кажется настолько полезным, что его уже нужно писать.

Ответы [ 5 ]

7 голосов
/ 02 февраля 2010

Как то так?

(defun chain-expander (forms)
  (cond ((null (cdr forms)) (car forms))
    (t `(let ((it ,(car forms)))
          ,(chain-expander (cdr forms))))))

(defun chain-counted-expander (forms counter)
  (cond ((null (cdr forms)) (car forms))
    (t (let* ((name (format nil "_~d" counter))
          (anaphora (or (find-symbol name) (intern name))))
         `(let ((,anaphora ,(car forms)))
        ,(chain-counted-expander (cdr forms) (1+ counter)))))))

(defmacro chain (&body forms)
  (chain-expander forms))

Если вы предпочитаете что-то, где _1, _2 и т. Д. Можно использовать, просто замените вызов CHAIN-EXPANDER на вызов CHAIN-COUNTED-EXPANDER (с вашим предпочтительным первым номером, я бы предложил 0 или 1). Обратите внимание, что он явно предназначен только для использования _ N в качестве ссылки, но изменить его так, чтобы он также связывал _ для каждого последующего уровня, не очень сложно.

4 голосов
/ 29 января 2010

Почему не просто

(f1 (f2 x (f1 x y)) z)

Или превратить это в функцию?

2 голосов
/ 17 июля 2012

Вы можете использовать макрос ablock из На Лиспе

(defmacro alambda (parms &body body)
  `(labels ((self ,parms ,@body))
     #'self))

(defmacro ablock (tag &rest args)
  `(block ,tag
     ,(funcall (alambda (args)
            (case (length args)
              (0 nil)    
          (1 (car args))
          (t `(let ((it ,(car args)))    ;; change it to _ 
            ,(self (cdr args))))))
       args)))

Макрос связывает значение предыдущего выражения с 'it', но вы можете изменить его на '_', если хотите. Конечно, вы также можете изменить имя на -> или как вам угодно.

1 голос
/ 30 января 2010
0 голосов
/ 17 июля 2012

Вам может быть интересен этот вопрос: Молчаливое программирование на Лиспе

Мой ответ на этот вопрос похож на ответ Ватина на этот вопрос, но без подсчета; в качестве примечания, я считаю, что подсчет опасно хрупок - вы можете вносить изменения в порядок ошибок при обновлении кода. Вероятно, лучше дать способ назвать предыдущие результаты, но на практике мне редко нужны результаты, отличные от последних. Если они вам нужны, возможно, вам следует написать функцию вместо выражения цепочки.

...