목록을 반복하여 여러 개의 디펀을 만들려면 어떻게해야합니까?


11

목록에있는 모든 테마에 대해 대화 형 기능을 동적으로 만들 수있는 emacs 구성 최적화를 위해 노력하고 있습니다.

아래는 내가 노력하고있는 구조의 단순화 된 버전입니다.

;; List containing names of functions that I want to create
(setq my/defun-list '(zz-abc
                      zz-def
                      zz-ghi))

;; Elisp macro to create an interactive defun whose name
;; is passed as the macro argument
(defmacro my/create-defun (defun-name)
  `(defun ,defun-name ()
     (interactive)
     (let ((fn-name (symbol-name ',defun-name)))
       (message "Testing creation of function %s" fn-name))))

;; Loop to call the above macro for each element in the list
;; DOES *NOT* WORK
(dolist (name my/defun-list)
  (my/create-defun name))

그러나 루프를 수동으로 풀면 작동합니다.

;; WORKS
(my/create-defun zz-abc)
(my/create-defun zz-def)
(my/create-defun zz-ghi)

그러나 아래는 기호 이름을 전달하는 곳에서 작동하지 않습니다 (루프 자체가 풀릴 때 발생하는 것일 수 있습니다). 매크로 인수 앞에 따옴표를 적어 둡니다.

;; DOES *NOT* WORK
(my/create-defun 'zz-abc)
(my/create-defun 'zz-def)
(my/create-defun 'zz-ghi)

최신 정보

@ wvxvw 의 도움 덕분에 마침내이 작업을 수행했습니다 !

@wvxvw가 제안했듯이 모든 유스 케이스에 대해 배치 생성 데펀을 사용하지는 않을 것입니다. 이것은라는 테마 의 작업을 수행 XYZ하는 defun을 생성하려는 특별한 유스 케이스 load-theme/XYZ입니다.

  • 활성화 될 수있는 다른 모든 테마 비활성화
  • 호출 load-theme에 대한XYZ
  • 해당 주제와 관련하여 더 많은 사용자 정의 작업을 수행합니다. 목록을 통해 각 테마의 사용자 지정 설정을 전달합니다 my/themes.

1
defuns안에 모두 넣습니다 progn. progn최상위 양식이 될 수 있습니다 (최상위 양식에 적용되는 모든 내용이 해당 내용에도 적용됨 progn). 그러나 나는 그런 식으로 함수를 생성하는 이론적 근거에 의문을 제기 할 것이다.
wvxvw

@ wvxvw 나는 제안을 이해하지 못했습니다. 루프에서 여러 번 호출하려는 하나의 defun 작성 매크로가 있습니다. 수동으로 풀린 예제는이 문제를 파악하는 동안 작동하고 작동하지 않는 것을 보여줍니다. 내 목표는 목록 대신 목록을 가지고 다양한 테마에 대한 대화 형 기능을 만드는 것 입니다. 현재 alist는 conses 로만 구성되어 있지만 각 테마에 대한 사용자 정의 속성이있는 목록으로 변환 할 계획입니다.
Kaushal Modi

글쎄, 당신은 (my/create-defun name)3 번 전화 했으므로 name3 번 이라는 함수를 정의해야합니다 .
Omar

답변:


13

다음은 설명하려는 시도와 제안입니다.

(defmacro my/create-defun (defun-name)
  `(defun ,defun-name ()
     (interactive)
     (let ((fn-name (symbol-name ',defun-name)))
       (message "Testing creation of function %s" fn-name))))

(dolist (name my/defun-list)
  ;; Macros are meant to create code, not execute it.  Think
  ;; about simply substituting the contents of your macro here
  ;; what would you expect it to do?
  (my/create-defun name))

(dolist (name my/defun-list)
  ;; This is not something a compiler (or interpreter)
  ;; can work with, it needs all sources of the code it
  ;; is going to execute
  (defun defun-name ()
    (interactive)
    (let ((fn-name (symbol-name 'defun-name)))
      (message "Testing creation of function %s" fn-name))))

;; This works because you, indeed created three defuns
(my/create-defun zz-abc)
(my/create-defun zz-def)
(my/create-defun zz-ghi)

;; This doesn't work because `defun' macro expect the name of
;; the function to be a symbol (but you are giving it a list
;; `(quote zz-abc)'.
(my/create-defun 'zz-abc)
(my/create-defun 'zz-def)
(my/create-defun 'zz-ghi)

이제이 문제를 해결해 봅시다.

;; Rewriting the original macro as a function and using a
;; macro to collect the generated forms gives:
(defun my/create-defun (defun-name)
  `(defun ,defun-name ()
     (interactive)
     (let ((fn-name (symbol-name ',defun-name)))
       (message "Testing creation of function %s" fn-name))))

(defmacro my/create-defuns (defuns)
  `(progn ,@(mapcar 'my/create-defun defuns)))

(macroexpand '(my/create-defuns (zz-abc zz-def zz-ghi)))
;; Just to make sure
(progn
  (defun zz-abc nil
    (interactive)
    (let ((fn-name (symbol-name (quote zz-abc))))
      (message "Testing creation of function %s" fn-name)))
  (defun zz-def nil
    (interactive)
    (let ((fn-name (symbol-name (quote zz-def))))
      (message "Testing creation of function %s" fn-name)))
  (defun zz-ghi nil
    (interactive)
    (let ((fn-name (symbol-name (quote zz-ghi))))
      (message "Testing creation of function %s" fn-name))))

변수에서 함수 이름을 읽는 예

(defvar my/functions '((func-1 . 1) (func-2 . 2) (func-3 . 3)))

(defun my/create-defun-n (defun-name n)
  `(defun ,defun-name ()
     (message "function: %s, n %d" ',defun-name ,n)))

(defmacro my/create-defuns-var ()
  `(progn ,@(mapcar
             (lambda (x) (my/create-defun-n (car x) (cdr x)))
             my/functions)))

(macroexpand '(my/create-defuns-var))
(progn
  (defun func-1 nil (message "function: %s, n %d" (quote func-1) 1))
  (defun func-2 nil (message "function: %s, n %d" (quote func-2) 2))
  (defun func-3 nil (message "function: %s, n %d" (quote func-3) 3)))

문제는 개념적인 문제였습니다. 매크로는 환경에서 코드를 읽고 싶을 때 코드를 생성하는 것입니다. 코드를 직접 실행하면 (프로그램 사용자로서) 이미 수행하기에 너무 늦습니다 (환경은 프로그램이 무엇인지 알아야합니다).


한계점 : 몇 가지를 함께 묶지 말 것을 권합니다 defuns. 그 이유는 디버그를 훨씬 더 복잡하게 만들기 때문입니다. 반복 정의에서 약간의 중복성은 유지 보수 단계에서 매우 효과적입니다 (그리고 유지 보수는 일반적으로 프로그램 수명에서 가장 긴 단계입니다).


4
나는 마지막 한계 참고 모든 굵은 대문자 :)에 있어야한다고 생각
ABO-ABO

감사! 그것은 훌륭한 정보입니다. 목록 mapcar과 함께 사용 하는 것을 알게 되 자마자 이것을 대답으로 받아 들일 것 입니다. 이것은 실제 사용 사례에서 작동하지 않는 것 같습니다. 최대한 빨리 이것으로 파헤쳐 볼게요.
Kaushal Modi

@kaushalmodi 당신은 (mapcar (lambda (x) (message "argument: %s" x)) some-alist)당신이 얻는 논쟁이 무엇인지보고 거기에서 일할 수 있습니다. 그것이 연관 목록이라면, 출력이 다음과 같다고 상상할 것입니다. 요법을 사용 하고 사용하여 argument: (foo . bar)액세스 할 수 있습니다 . foocarbarcdr
wvxvw

예, 동일한 작업을 수행 했지만 ( 및 nth대신 fn을 사용했습니다 ) 체크인 오류가 발생했습니다. 나는 목록을 입력으로 제공했지만 여전히 mapcar는 그것이 시퀀스라고 생각하지 않았습니다. 내가했다면 , 그것은 넌이 아니었다. 혼란 스러워요. 아직 디버깅을해야합니다. carcadrsequencepmapcar(sequencep my-alist)
Kaushal Modi

: @kaushalmodi 나는 두 가지 이유를 상상 my-alist했다 nil또는 그래서 당신이 따옴표를 잊었 (또는 별도 추가) my-alist중 하나를 상징이었다, 또는 뭔가 다른 것으로 더욱 평가 하였다. 새 코드로 질문을 확장하여보다 쉽게 ​​답변 할 수 있습니다.
wvxvw

2
(dolist (fun '(foo bar baz))
  (defalias fun (lambda (a)
                  "I'm a function defined in `dolist'!"
                  (interactive)
                  (message a))))
(bar "See? No macro!")

정확히 디펀은 아니지만 왜 그렇지 않습니까? :피


0

내 init에 다음이 있습니다.

(my/work-properties '("hostname" "username" "location"))

(defmacro jlp/make-def (name props doc &rest body)
  "Shortcut to programatically create new functions"
  (let ((funsymbol (intern name)))
    `(defun ,funsymbol ,props ,doc ,@body)))

(defun my/make-work-props (properties)
  "Create functions to retrieve properties from Org headlines."
  (dolist (prop properties)
    (let ((funsym   (format "my/org-get-%s" prop))
          (property (intern (format ":%s" (upcase prop))))
          (doc      (format "Retrieves `%s' from current headline"
                            (upcase prop)))
          (err (format "%s is not set" (capitalize prop))))
      (eval
       `(jlp/make-def ,funsym
                      ()
                      ,doc
                      (interactive)
                      (let ((x (or
                                (save-excursion
                                  (org-back-to-heading)
                                  (org-element-property
                                   ,property
                                   (org-element-at-point)))
                                (user-error ,err))))
                        (message "%s" x)
                         (kill-new x)))))))

(my/make-work-props my/org-work-properties)

아마도 필요한 것보다 약간 더 복잡 할 수 있지만 (특히 여분의 평가) 속성에 필요한 defuns를 생성 할 수 있습니다 (문자열에 올바른 정보가 담긴 docstring을 포함).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.