Проблема с написанием инфиксного макроса в Clojure - PullRequest
0 голосов
/ 19 октября 2019

Я пытаюсь написать макрос инфиксного Clojure, но получаю ошибку компиляции, которую я не понимаю.

Он должен вызывать вызовы функций из синтаксиса регулярного математического выражения:

(macroexpand '(infix 3 * (2 + 1)))
;; => (* 3 (+ 2 1))

Я пытался переключить оператор list в кавычку, но он не работал.

Макрос:

(defmacro functionize [macro]
  `(fn [& args#] (eval (cons '~macro args#))))

(defmacro infix
  ([n]
   (if (not (or (number? n) (fn? n)))
     `(~(apply (functionize infix) n))
     n))
  ([fir sec & res]
   (list sec (infix fir) (infix res))))

Ошибка:

1. Caused by java.lang.IllegalArgumentException
   Don't know how to create ISeq from: clojure.lang.Symbol

Ошибка для последней строки, для первого вызова для infix.

1 Ответ

2 голосов
/ 21 октября 2019

Я вижу по крайней мере одну возможную ошибку в вашем коде: [fir sec & res] должно быть [fir sec res], так как вам нужен третий аргумент, а не список всех аргументов. Это все еще не решает проблемы в вашем коде. Главное, что вы переосмысливаете это (eval и прочее)

Я бы, наверное, использовал что-то вроде этого:

(defmacro infix [n]
  (if (list? n)
    (let [[arg1 op arg2] n]
      `(~op (infix ~arg1) (infix ~arg2)))
    n))

user> (clojure.walk/macroexpand-all '(infix (1 + ((6 - (3 / 7)) * 3))))
;;=> (+ 1 (* (- 6 (/ 3 7)) 3))

user> (infix (1 + ((6 - (3 / 7)) * 3)))
;;=> 124/7

ОБНОВЛЕНИЕ

чтобы опустить скобки, вы можете обновить его следующим образом:

(defn unwrap-arg [restargs]
  (if (= 1 (count restargs))
    (first restargs)
    restargs))

(defmacro infix [n]
  (if (list? n)
    (let [[arg1 op & arg2] n]
      `(~op (infix ~arg1) (infix ~(unwrap-arg arg2))))
    n))

user> (clojure.walk/macroexpand-all '(infix (1 + 2 + (10 - (4 / 10)) + (4 * 5))))
;;=> (+ 1 (+ 2 (+ (- 10 (/ 4 10)) (* 4 5))))

user> (infix (1 + 2 + (10 - (4 / 10)) + (4 * 5)))
;;=> 163/5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...