(루프 …) 안에 백틱/쉼표 관용구를 사용하는 것이 맞나요?

StackOverflow https://stackoverflow.com/questions/101487

  •  01-07-2019
  •  | 
  •  

문제

다음과 같은 루프에서 포인트(consed 정수)를 수집하는 코드가 있습니다.

(loop
    for x from 1   to     100
    for y from 100 downto 1
        collect `(,x . ,y))

내 질문은 사용하는 것이 올바른지입니다. `(,x . ,y) 이러한 상황에서?

편집하다:이 샘플은 100x100 항목의 테이블을 생성하는 것에 관한 것이 아닙니다. 여기의 코드는 두 개의 루프 변수의 사용과 해당 값의 구성을 보여줍니다.이를 명확하게 하기 위해 루프를 편집했습니다.내가 사용하는 실제 루프는 여러 다른 함수에 따라 달라지며(그리고 함수 자체의 일부임) 호출을 리터럴 정수로 바꾸고 함수에서 루프를 꺼내는 것이 더 합리적입니다.

도움이 되었습니까?

해결책

그냥 하는 것이 훨씬 '더 나을' 것입니다(단점 x y).

하지만 질문에 답하세요, 그렇게 하는 데 아무런 문제가 없습니다 :) (조금 느리게 만드는 것을 제외하고).

다른 팁

여기서 답은 자원 활용이라고 생각합니다. 이 게시물)

예를 들어 클립에서:

[1]> (time
         (progn
             (loop
                 for x from 1 to 100000
                 for y from 1 to 100000 do
                     collect (cons x y))
         ()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
         CL.
Real time: 0.469 sec.
Run time: 0.468 sec.
Space: 1609084 Bytes
GC: 1, GC time: 0.015 sec.
NIL
[2]> (time
         (progn
             (loop
                 for x from 1 to 100000
                 for y from 1 to 100000 do
                     collect `(,x . ,y)) ;`
         ()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
         CL.
Real time: 0.969 sec.
Run time: 0.969 sec.
Space: 10409084 Bytes
GC: 15, GC time: 0.172 sec.
NIL
[3]>

DSM:코드에 몇 가지 이상한 점이 있습니다 여기.참고하세요

(loop for x from 1 to 100000
  for y from 1 to 100000 do
  collect `(,x . ,y))

다음과 같습니다:

(loop for x from 1 to 100
   collecting (cons x x))

아마도 당신이 의도한 것이 아닐 수도 있습니다.세 가지 사항에 유의하세요.첫째, 작성한 방식대로 x와 y는 동일한 역할을 합니다.아마도 루프를 중첩하려고 했을 것입니다.둘째, 뒤에 오는 lisp 형식이 없기 때문에 y 이후의 작업이 올바르지 않습니다.셋째, 여기에서 백틱 접근 방식을 사용할 수 있다는 점은 맞습니다. 그러나 코드를 읽기 어렵게 만들고 관용적이지 않으므로 피하는 것이 가장 좋습니다.

실제로 의도한 것이 무엇인지 추측하면 다음과 같은 작업을 수행할 수 있습니다(루프 사용).

(loop for x from 1 to 100 appending 
  (loop for y from 1 to 100 collecting (cons x y)))

Kyle과 같은 루프 매크로가 마음에 들지 않으면 다음과 같은 다른 반복 구성을 사용할 수 있습니다.

(let ((list nil)) 
   (dotimes (n 100) ;; 0 based count, you will have to add 1 to get 1 .. 100
     (dotimes (m 100) 
       (push (cons n m) list)))
   (nreverse list))

이런 종류의 작업을 많이 수행하는 경우 목록 교차를 위한 보다 일반적인 함수를 작성한 다음 이 정수 목록을 전달해야 할 것입니다.

루프뿐만 아니라 반복에 문제가 있는 경우 이러한 종류의 작업을 재귀적으로 수행할 수 있습니다(그러나 이는 계획이 아니므로 구현 시 TCO가 보장되지 않을 수 있습니다).Kyle이 보여주는 함수 "genint" 여기 일반적인(표준은 아님) 기능 iota의 변형입니다.그러나 목록에 추가하는 것은 나쁜 생각입니다.다음과 같은 동등한 구현:

(defun iota (n &optional (start 0))
  (let ((end (+ n start)))
    (labels ((next (n)
               (when (< n end) 
                 (cons n (next (1+ n))))))
      (next start))))

훨씬 더 효율적이어야 하지만 여전히 꼬리 호출은 아닙니다.참고 저는 이것을 보다 일반적인 0 기반으로 설정했지만 1이나 다른 정수에서 시작하는 선택적 매개 변수를 제공했습니다.물론 위의 내용은 다음과 같이 작성할 수 있습니다.

(defun iota (n &optional (start 0))
  (loop repeat n 
     for i from start collecting i))

큰 논쟁으로 인해 스택을 날리지 않는다는 장점이 있습니다.구현이 마무리 호출 제거를 지원하는 경우 다음과 같이 수행하여 재귀가 제자리에서 벗어나는 것을 방지할 수도 있습니다.

(defun iota (n &optional (start 0))
  (labels ((next (i list)
             (if (>= i (+ n start))
                 nil
                 (next (1+ i) (cons i list)))))
    (next start nil)))

도움이 되었기를 바랍니다!

왜 안되지?

(cons x y)

그런데 CLISP에서 코드를 실행하려고 했는데 예상대로 작동하지 않았습니다.나는 루프 매크로를 별로 좋아하지 않기 때문에 동일한 작업을 재귀적으로 수행하는 방법은 다음과 같습니다.

(defun genint (stop)
  (if (= stop 1) '(1)
      (append (genint (- stop 1)) (list stop))))

(defun genpairs (x y)
  (let ((row (mapcar #'(lambda (y)
                        (cons x y))
                        (genint y))))
    (if (= x 0) row
        (append (genpairs (- x 1) y)
                row))))

(genpairs 100 100)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top