Ошибка типа при запуске общего макроса lisp, который пытается вывести код Javascript. Почему?

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

Это код, который я написал:

;;;; This program is aimed at creating a very high level language that writes
;;;; complex and formally correct Javascript with minimal code.

(defvar *namespace* nil)

(defmacro conc (var &body body)
  `(setf ,var (concatenate 'string output ,@body)))

(defun public-var (name value)
  (let ((output ""))
    (conc output *namespace* "." name " = " value ";")
    output))

(defmacro namespace (ns &rest contents)
  `(let ((*namespace* (concatenate 'string "window." ,ns)) (output ""))
     (conc output "(function(ns){")
     (let ((*namespace* "ns"))
       ,(loop for e in contents collect `(conc output (apply ,(first e) (list ,@(rest e))))))
     (conc output "}(" *namespace* " = " *namespace* " || {}));")
     output))

Идея состоит в том, чтобы иметь возможность писать такой код:

(namespace "namespace"
  (#'public-var "hello" "world")
  (#'public-var "something" "else"))

и получить этот вывод:

(function(ns){
  ns.hello = world;
  ns.something = else;
}(window.namespace = window.namespace || {}));

Я знаю, что мне все еще нужно поработать над отступом вывода и разрывами строк, но это еще не главное (это должны быть первые строительные блоки для абстрагирования более сложной логики). Проблема в том, что я получаю эту ошибку, и я не могу понять, почему (серьезно, я уже часами исследовал и пробовал разные вещи):

Illegal function object:
(CONC OUTPUT (APPLY #'PUBLIC-VAR (LIST "ciao" "mondo"))).
   [Condition of type TYPE-ERROR]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME's top level.
 2: [ABORT] Abort entirely from this (lisp) process.

Backtrace:
  0: (IDE.BASE::IDE-INVOKE-DEBUGGER-FROM-NON-CG-PROCESS "Error" #<TYPE-ERROR @ #x22de54b2> T NIL NIL)
  1: (ERROR TYPE-ERROR :DATUM (CONC OUTPUT (APPLY #'PUBLIC-VAR (LIST "ciao" "mondo"))) :EXPECTED-TYPE (OR SYMBOL FUNCTION) ...)
  2: ((CONC OUTPUT (APPLY #'PUBLIC-VAR (LIST "ciao" "mondo"))))
  3: (LET ((*NAMESPACE* "ns")) ((CONC OUTPUT (APPLY #'PUBLIC-VAR #))))
  4: (LET ((*NAMESPACE* (CONCATENATE 'STRING "window." "webtrekk_dl")) (OUTPUT "")) ..)
  5: (EVAL (NAMESPACE "webtrekk_dl" (#'PUBLIC-VAR "ciao" "mondo")))
 --more--

Я также пробовал отдельные части. Например это:

 (let ((output ""))  (CONC OUTPUT (APPLY #'PUBLIC-VAR (LIST "ciao" "mondo"))))

работает и дает мне этот вывод:

".ciao = mondo;"

Любая идея, что я делаю неправильно?


person roccobarbi    schedule 05.11.2018    source источник
comment
Используйте macroexpand-1 и pprint для просмотра макрорасширения вашего примера (namespace ...). Тогда вы легко увидите ошибку.   -  person Rainer Joswig    schedule 05.11.2018


Ответы (1)


,(loop for e in contents collect `(conc output …))

Это возвращает список:

((conc output …)
 (conc output …)
 …)

Список оценивается путем применения оператора, который является первым элементом списка, к аргументам.

Допустимые операторы — это только символы или лямбда-формы. Форма conc недействительна как оператор. Скорее всего, вы хотели что-то вроде:

(progn
  (conc output …)
  …)

В качестве примечания: я не знаю, что на самом деле должен делать ваш вывод JavaScript. Он игнорирует параметр ns и устанавливает две новые глобальные переменные. Это не кажется полезным.

person Svante    schedule 06.11.2018
comment
Большое спасибо за объяснение. На самом деле, как новичок, мне было бы трудно это заметить. Что касается Javascript, я исправлю его, как только буду перед компьютером, для дальнейшего использования. забыл добавить нс. перед каждой переменной в выходных данных примера. - person roccobarbi; 06.11.2018