여러 변수에 동일한 값을 할당 하시겠습니까?


12

때로는 여러 변수에 동일한 값을 설정해야합니다.

파이썬에서는 할 수 있습니다

f_loc1 = f_loc2 = "/foo/bar"

그러나 간혹, 나는 쓰고있다

(setq f_loc1 "/foo/bar" f_loc2 "/foo/bar")

"/foo/bar"한 번만 사용하여이를 달성 할 수있는 방법이 있는지 궁금합니다 .


1
안녕하세요, Chillar, @tarsius '답변을 허용되는 답변으로 선택해 주시겠습니까? 내 대답은 당신이 원하는 것을 제공하는 솔루션을 보여 주지만, 말했듯 이이 논란의 여지가있는 인공 도전을 해결하지만 실제로는별로 유용하지 않은 "일종의 운동"입니다. tarsuis는 그의 대답에서이 명백한 고려 사항을 입증하기 위해 많은 노력을 기울 였으므로, 그의 대답은 "올바른 것"이어야하므로 모든 사람이 다시 행복하다고 생각합니다.
Mark Karpov

1
여러 변수에 동일한 값을 할당해야한다는 것은 구문 설탕을
감추지

1
만약 희망 세트에 @lunaryorn source& target시작 부분에 동일한 경로와 나는 변경 될 수 있습니다 target나중에 어떻게 다음을 설정?
ChillarAnand

더 많은 코드를 표시하여 사용 사례에 대해 "가변"이라는 의미를 알 수 있습니다. 즉, 어떤 종류의 변수를 설정하려고합니까? @JordonBiondo의 답변에 대한 내 의견을 참조하십시오.
Drew

답변:


21

setq 값을 반환하므로 다음과 같이 할 수 있습니다.

(setq f-loc1 (setq f-loc2 "/foo/bar"))

그것에 의존하고 싶지 않다면 다음을 사용하십시오.

(setq f-loc1 "/foo/bar" f-loc2 f-loc1)

개인적으로 나는 후자를 피하고 대신 다음과 같이 씁니다.

(setq f-loc1 "/foo/bar"
      f-loc2 f-loc1)

또는

(setq f-loc1 "/foo/bar")
(setq f-loc2 f-loc1)

그리고 첫 번째 접근 방식은 실제로 의도를 강조 하는 대체 상황 이나 대안이 두 번째 접근 방식 또는 다른 방법을 사용하는 경우에만 사용하는 것 progn입니다.


위의 내용이 만족스러운 경우 여기에서 읽기를 중단 할 수 있습니다. 그러나 나는 이것이 당신과 다른 사람들에게 매크로를 남용하지 말라고 경고 할 수있는 좋은 기회라고 생각합니다.


마지막으로, setq-every"이것이 lisp이고 우리가 할 수 있기 때문에" 와 같은 매크로를 작성하고 싶은 유혹 이지만, 그렇게하지 않는 것이 좋습니다. 당신은 그것을함으로써 거의 얻을 수 없습니다 :

(setq-every value a b)
   vs
(setq a (setq b value))

그러나 동시에 다른 독자가 코드를 읽고 어떤 일이 발생하는지 확인하기가 훨씬 어렵습니다. setq-every다양한 방법으로 구현 될 수 있으며 다른 사용자 (미래를 포함하여)는이를 사용하는 코드를 살펴보면 저자가 선택한 사람을 알 수 없습니다. [원래 여기에 몇 가지 예를 들었지만, 이는 비꼬는 것으로 간주되어 누군가에 의해 광란이되었습니다.]

당신은 당신이 볼 때마다 그 정신적 오버 헤드를 처리 setq-every하거나 하나의 추가 캐릭터와 함께 살 수 있습니다. (적어도 두 개의 변수 만 설정해야하지만 한 번에 두 개 이상의 변수를 동일한 값으로 설정해야한다는 것을 기억할 수 없습니다. 그렇게 해야하는 경우 다른 문제가있을 수 있습니다 코드와 함께)

반면에이 매크로를 실제로 6 십회 이상 사용하려는 경우 추가 간접적 가치가있을 수 있습니다. 예를 들어 내가 좋아하는 매크로 사용 --when-let로부터 dash.el라이브러리를. 그것은 내 코드에서 그것을 처음 접하는 사람들에게는 더 어렵게 만듭니다. 그러나 그 이해의 어려움을 극복하는 것은 단지 몇 번 이상 사용되며 적어도 내 견해로는 코드를 더 읽기 쉽기 때문에 가치가 있습니다. .

에 동일하게 적용된다고 주장 할 수도 setq-every있지만이 특정 매크로가 몇 번 이상 사용될 가능성은 매우 낮습니다. 일반적으로 매크로 정의 (doc-string 포함)가 매크로를 사용하는 것보다 더 많은 코드를 추가하면 매크로가 과도하게 사용되는 경우가 많습니다 (거의 사실이 아닐 수도 있음).


1
하나의 var를 설정 setq하면 새로운 값을 참조 할 수 있으므로이 괴물도 사용할 수 있습니다. (setq a 10 b a c a d a e a)abcd와 e를 10으로 설정합니다.
Jordon Biondo

1
@JordonBiondo, 예. 그러나 OP의 목표는 코드에서 반복을 줄이는 것입니다 :-)
Mark Karpov

3
거시적 학대에 대한 경고로 +10을 드리고 싶습니다!
lunaryorn

매크로 모범 사례에 대한 퀘스트를 만들었습니다. emacs.stackexchange.com/questions/21015 . @tarsius와 다른 사람들이 큰 대답을 바랍니다.
Yasushi Shoji

13

원하는 것을하는 매크로

일종의 연습으로 :

(defmacro setq-every (value &rest vars)
  "Set every variable from VARS to value VALUE."
  `(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))

이제 시도해보십시오.

(setq-every "/foo/bar" f-loc1 f-loc2)

작동 원리

사람들은 그것이 어떻게 작동하는지 궁금하기 때문에 (설명에 따라) 여기에 설명이 있습니다. 매크로를 작성하는 방법을 배우려면 좋은 Lisp 책을 선택하십시오 (예, Common Lisp, Emacs Lisp에서도 동일한 작업을 수행 할 수 있지만 Common Lisp은 조금 더 강력하고 더 나은 책을 가지고 있습니다) IMHO.

매크로는 원시 코드에서 작동합니다. 매크로는 함수와 달리 인수를 평가하지 않습니다. 그래서 우리는 여기에 대한 평가되지 않은 value컬렉션을 가지고 있습니다 vars.

progn여러 setq양식을 하나로 그룹화합니다 . 이건 :

(mapcar (lambda (x) (list 'setq x value)) vars)

setqOP의 예를 사용하여 양식 목록을 생성 하면됩니다.

((setq f-loc1 "/foo/bar") (setq f-loc2 "/foo/bar"))

보시다시피, 양식은 역 따옴표 양식 안에 있으며 앞에 쉼표가 붙습니다 ,. 내부 인용 된 양식은 모든 것이 일반적으로 인용되지만 , 일시적으로 "켜짐"평가되므로 전체 mapcar가 거시 확장 시간에 평가됩니다.

마지막으로 s를 사용하여 @목록에서 외부 괄호를 제거 setq하여 다음을 얻습니다.

(progn
  (setq f-loc1 "/foo/bar")
  (setq f-loc2 "/foo/bar"))

매크로는 소스 코드를 임의로 변형시킬 수 있습니다.

경고

다음은 작은 경고입니다.이 매크로는 본질적으로 다음과 같이 확장되기 때문에 첫 번째 인수는 여러 번 평가됩니다.

(progn
  (setq f-loc1 "/foo/bar")
  (setq f-loc2 "/foo/bar"))

여기에 변수 또는 문자열이 있으면 괜찮지 만 다음과 같이 작성하면됩니다.

(setq-every (my-function-with-side-effects) f-loc1 f-loc2)

그런 다음 함수가 두 번 이상 호출됩니다. 바람직하지 않을 수 있습니다. 다음은 MMT 패키지once-only 에서 사용 가능 하도록 수정하는 방법입니다 .

(defmacro setq-every (value &rest vars)
  "Set every variable from VARS to value VALUE.

VALUE is only evaluated once."
  (mmt-once-only (value)
    `(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars))))

그리고 문제는 사라졌습니다.


1
이것이 어떻게 작동하는지와이 코드가 무엇을하고 있는지에 대한 설명을 추가 할 수 있다면 좋을 것입니다. 그래서 다음에 사람들은 이와 같은 것을 스스로 작성할 수 있습니다 :)
clemera

value매크로 확장 시간 에 평가하고 싶지 않습니다 .
tarsius

@tarsius, 나는하지 않습니다 : (macroexpand '(setq-every user-emacs-directory f-loc1 f-loc2))-> (progn (setq f-loc1 user-emacs-directory) (setq f-loc2 user-emacs-directory)). value매크로 확장 시간에 평가 된 경우 실제 문자열로 대체됩니다. 대신에 부작용이있는 함수 호출을 넣을 수 있습니다. value확장 코드가 실행될 때까지 평가되지 않으므로 시도하십시오. value매크로의 인수로 자동 평가되지 않습니다. 실제 문제는 value바람직하지 않은 경우 여러 번 평가되며 once-only여기에 도움이 될 수 있습니다.
Mark Karpov

1
mmt-once-only(외부 장치가 필요함) 대신을 사용할 수 있습니다 macroexp-let2.
YoungFrog

2
어. 이 질문 은 매크로 set를 래핑하지 않고로 반복을 사용하도록 요구합니다 setq. 또는 setq인수 반복을 포함하여 여러 인수와 함께 사용하십시오 .
Drew

7

lisp에서 기호를 사용하고 조작 할 수 있으므로 기호 목록을 반복하여 사용하면 set됩니다.

(dolist (var '(foo bar baz)) (set var 10))

(mapc (lambda (var) (set var 10)) '(foo bar baz))

(loop for var in '(foo bar baz) do (set var 11))

(--each '(foo bar baz) (set it 10))

2
그러나 어휘 적으로 바인드 된 변수에는 작동하지 않습니다.
npostavs

@npostavs : 맞습니다. 그러나 OP가 원하거나 필요로하는 것일 수도 있습니다. 그는 어휘 변수를 사용하지 않는다면 분명히 갈 길입니다. 그러나 "변수"는 모호하므로 일반적으로 질문은 모든 종류의 변수를 의미 할 수 있습니다. 실제 사용 사례는 잘 나와 있지 않습니다 (IMO).
Drew
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.