Исключение компилятора java.lang.Исключение из IllegalArgumentException: не знаю, как создать ISeq из: clojure.lang.Символ

#dictionary #clojure #macros #symbols

#словарь #clojure #макросы #символов

Вопрос:

Мне нужно использовать мой макрос как функции map, но я не знаю, как я могу это сделать. Объясните мне, пожалуйста. Мой макрос «get-conj» создает двоичные функции, которые состоят из объединения нескольких переменных.

Я уже пробовал поместить макрос в лямбда-функцию, но это не работает. Также я проверил макрос, и это правильно.

 ; this call of map doesn't work.
(map #(get-conj [x0 x1] %) [[1 0] [0 1] [0 0]])

;but just call of get-conj works fine.
(def conjunction (get-conj [x0 x1]  [1 0]) ==> x0 amp; not(x1)
(conjunction true false) ; ==> true 
(conjunction true true)  ; ==> false

; bit is 1 or 0 value
(defn get-var [bit]
  (if (zero? bit)
    not
    identity))

(defn get-args [n]
  (vec (map #(read-string (s/join [x %])) (range n))))

(defn mapdef [fns args] (map #(%1 %2) fns args))

;; the macro builds binary functions which consist of 
(defmacro get-conj [args bits] ;conjunction of few variables.
  (let [vars (map get-var bits)]
   `(fn ~args
       (every? identity (mapdef '~vars ~args)))))


I want to get list of binary-functions.
  

Трассировка стека для:

 (map #(get-conj [x0 x1] %) [[1 0] [0 1] [0 0]])
 2. Unhandled clojure.lang.Compiler$CompilerException
       Error compiling *cider-repl clojure/ex1:localhost:40769(clj)* at (1252:16)

             Compiler.java: 7010  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6773  clojure.lang.Compiler/analyze
             Compiler.java: 6729  clojure.lang.Compiler/analyze
             Compiler.java: 6100  clojure.lang.Compiler$BodyExpr$Parser/parse
             Compiler.java: 5460  clojure.lang.Compiler$FnMethod/parse
             Compiler.java: 4022  clojure.lang.Compiler$FnExpr/parse
             Compiler.java: 7001  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6773  clojure.lang.Compiler/analyze
             Compiler.java: 6729  clojure.lang.Compiler/analyze
             Compiler.java: 3881  clojure.lang.Compiler$InvokeExpr/parse
             Compiler.java: 7005  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6773  clojure.lang.Compiler/analyze
             Compiler.java: 6729  clojure.lang.Compiler/analyze
             Compiler.java: 6100  clojure.lang.Compiler$BodyExpr$Parser/parse
             Compiler.java: 5460  clojure.lang.Compiler$FnMethod/parse
             Compiler.java: 4022  clojure.lang.Compiler$FnExpr/parse
             Compiler.java: 7001  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6773  clojure.lang.Compiler/analyze
             Compiler.java: 7059  clojure.lang.Compiler/eval
             Compiler.java: 7025  clojure.lang.Compiler/eval
                  core.clj: 3206  clojure.core/eval
                  core.clj: 3202  clojure.core/eval
                  main.clj:  243  clojure.main/repl/read-eval-print/fn
                  main.clj:  243  clojure.main/repl/read-eval-print
                  main.clj:  261  clojure.main/repl/fn
                  main.clj:  261  clojure.main/repl
                  main.clj:  177  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  657  clojure.core/apply
                  core.clj:  652  clojure.core/apply
                regrow.clj:   18  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   79  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   55  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  142  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  171  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  170  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  748  java.lang.Thread/run

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

                   RT.java:  550  clojure.lang.RT/seqFrom
                   RT.java:  530  clojure.lang.RT/seq
                  core.clj:  137  clojure.core/seq
                  core.clj: 2738  clojure.core/map/fn
              LazySeq.java:   40  clojure.lang.LazySeq/sval
              LazySeq.java:   49  clojure.lang.LazySeq/seq
                   RT.java:  528  clojure.lang.RT/seq
                  core.clj:  137  clojure.core/seq
            core_print.clj:   53  clojure.core/print-sequential
            core_print.clj:  174  clojure.core/fn
            core_print.clj:  174  clojure.core/fn
              MultiFn.java:  233  clojure.lang.MultiFn/invoke
                  core.clj: 3666  clojure.core/pr-on
                  core.clj: 3669  clojure.core/pr
                  core.clj: 3669  clojure.core/pr
                  AFn.java:  154  clojure.lang.AFn/applyToHelper
               RestFn.java:  132  clojure.lang.RestFn/applyTo
                  core.clj:  657  clojure.core/apply
                  core.clj: 4702  clojure.core/pr-str
                  core.clj: 4702  clojure.core/pr-str
               RestFn.java:  408  clojure.lang.RestFn/invoke
                 debug.clj:  188  cider.nrepl.middleware.debug/pr-short
                 debug.clj:  182  cider.nrepl.middleware.debug/pr-short
                 debug.clj:  334  cider.nrepl.middleware.debug/read-debug-command
                 debug.clj:  312  cider.nrepl.middleware.debug/read-debug-command
                 debug.clj:  506  cider.nrepl.middleware.debug/break
                 debug.clj:  488  cider.nrepl.middleware.debug/break
                      REPL:   49  ex1.bfg/eval20195/get-conj
                  AFn.java:  165  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  Var.java:  702  clojure.lang.Var/applyTo
             Compiler.java: 6912  clojure.lang.Compiler/macroexpand1
             Compiler.java: 6989  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6773  clojure.lang.Compiler/analyze
             Compiler.java: 6729  clojure.lang.Compiler/analyze
             Compiler.java: 6100  clojure.lang.Compiler$BodyExpr$Parser/parse
             Compiler.java: 5460  clojure.lang.Compiler$FnMethod/parse
             Compiler.java: 4022  clojure.lang.Compiler$FnExpr/parse
             Compiler.java: 7001  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6773  clojure.lang.Compiler/analyze
             Compiler.java: 6729  clojure.lang.Compiler/analyze
             Compiler.java: 3881  clojure.lang.Compiler$InvokeExpr/parse
             Compiler.java: 7005  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6773  clojure.lang.Compiler/analyze
             Compiler.java: 6729  clojure.lang.Compiler/analyze
             Compiler.java: 6100  clojure.lang.Compiler$BodyExpr$Parser/parse
             Compiler.java: 5460  clojure.lang.Compiler$FnMethod/parse
             Compiler.java: 4022  clojure.lang.Compiler$FnExpr/parse
             Compiler.java: 7001  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6773  clojure.lang.Compiler/analyze
             Compiler.java: 7059  clojure.lang.Compiler/eval
             Compiler.java: 7025  clojure.lang.Compiler/eval
                  core.clj: 3206  clojure.core/eval
                  core.clj: 3202  clojure.core/eval
                  main.clj:  243  clojure.main/repl/read-eval-print/fn
                  main.clj:  243  clojure.main/repl/read-eval-print
                  main.clj:  261  clojure.main/repl/fn
                  main.clj:  261  clojure.main/repl
                  main.clj:  177  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  657  clojure.core/apply
                  core.clj:  652  clojure.core/apply
                regrow.clj:   18  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   79  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   55  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  142  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  171  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  170  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  748  java.lang.Thread/run
  

Комментарии:

1. Опубликуйте полную ошибку с помощью trace вместе с примером ввода, который вы используете.

2. bits Передается как символ? Вы уверены, что вам нужен макрос здесь?

3. @Carcigenicate, я добавил трассировку стека. И да, bits является символом. Я хочу получить список сгенерированных двоичных функций, поэтому я пытаюсь написать макрос. Я думаю, что могу сделать это с помощью макросов. Я понимаю, что макросы вычисляются раньше, чем функции, но я не знаю, как я должен это использовать.

4. Подумайте о том, что bits задано, что get-conj является макросом. Это не те данные, которые вы ожидаете.

5. @Carcigenicate, я думал об этом. Спасибо!

Ответ №1:

Если я правильно понимаю ваш код, у вас есть набор битов, скажем [0 1 0] . Каждый бит указывает, следует ли отрицать соответствующий аргумент или нет. Затем вы хотите вычислить объединение этих, возможно, отрицаемых аргументов. Итак, если бы ваши аргументы были a , b и c с теми битами, которые вы хотели бы вычислить (and (not a) b (not c)) , верно?

Как другие уже намекали в комментариях, вам не нужны макросы для достижения этого.

Вот функция get-conj , которая в качестве аргументов принимает последовательность битов и возвращает новую функцию, которая выполняет то, что я объяснил выше:

 (defn get-conj [bits]
  (fn [amp; args]
    {:pre [(= (count bits)
              (count args))]}
    (every? identity (map (fn [bit arg]
                            (if (zero? bit)
                              (not arg) arg))
                          bits args))))
  

Обратите внимание, что get-conj функция теперь принимает только один аргумент, который является bits .

И приведенный вами пример кода работает (с небольшими изменениями):

 (map get-conj  [[1 0] [0 1] [0 0]])

(def conjunction (get-conj [1 0]))

(assert (conjunction true false))
(assert (not (conjunction true true)))
  

Макросы лучше всего использовать в ситуациях, когда функций недостаточно, таких как небольшие синтаксические настройки (например, when , -> ) или создание мини-языков, таких как core.async или англиканский вероятностный язык программирования.

Комментарии:

1. Хорошо, вы правы. Это означает, что я могу реализовать свой алгоритм без использования макросов. Большое спасибо! Я оценил вашу помощь!

Ответ №2:

Это связано с проблемами оценки аргументации, когда синтаксису #() передается символ макроса… Я считаю, что это «принципиально та же проблема, которая предотвращает вложенные макросы reader [т. Е. вы не можете #(x # (y))]. Возможно, я не лучший человек, который мог бы это объяснить.

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

 (defn macro-partial [macro-name amp; supplied-args] 
  (apply partial (comp eval macroexpand list) macro-name supplied-args))

;produces a list of functions created by get-conj.
(map (macro-partial 'get-conj '[x0 x1]) [[1 0] [0 1] [0 0]])

;call like this
(map apply 
      (map (macro-partial 'get-conj '[x0 x1]) [[1 0] [0 1] [0 0]])
      (repeat '(1 2)))