'(a. b)는 실제로 목록입니까?


15

나는 실제로 .표기법 과 혼동 됩니다. 가 '(a . b)목록은?

(listp '(a . b))반환 t하지만 길이를 알고 싶을 때 (length '(a . b))오류가 발생 Wrong type argument: listp, b합니다. 다른 기능 nth,mapcar등도 마찬가지입니다 . 모두 같은 오류가 발생합니다.

'(a b)과를 구별 할 수있는 기능이 '(a . b)있습니까?


컨텍스트 :의 재귀 버전을 구현하려고 할 때이 문제가 발생했습니다 mapcar. 여기 내 구현입니다

(defun true-listp (object)
"Return non-`nil' if OBJECT is a true list."
(and (listp object)  (null (cdr (last object)))))

(defun recursive-mapcar (func list)
"Evaluates func on elements of the list, then on elements of elements  of the list and so forth." 
(let ((output nil))
(flet ((comp (a b) nil)
       (call-fun-and-save (x) (add-to-list 'output (funcall func x) t 'comp))
       (recursion (l)
                  (mapcar
                   (lambda (x)
                     (call-fun-and-save x)
                     (if (and (true-listp x))  ;; HERE I use true-listp, testing for list or cons is not sufficient
                         (recursion x)))
                    l)))
   (recursion list))
  output))

이것을 사용하여 구문 분석 된 HTML에서 모든 특정 태그를 추출합니다. html파싱하는 예

;; buffer 'html'
<html>
<body>
<table style="width:100%">
  <tr>  <td>Jill</td>  <td>Smith</td>  <td>50</td> </tr>
  <tr>  <td>Eve</td>   <td>Jackson</td>   <td>94</td> </tr>
</table>
</body>
</html>

그런 다음 모든 것을 추출합니다 <td>.

(with-current-buffer (get-buffer "html")
  (let ((data (libxml-parse-html-region (point-max) (point-min))))

    ;; gat only <td> tags
    (-non-nil
     (recursive-mapcar
      (lambda(x) (and (consp x) (equal 'td (car x)) x))
      data))
    data
    )
  )

1
전혀 없다 true-list-p가 그것을 제공하는 유용한 충분 발견되지 않은 이유만으로 Elisp있다. 사실, 목록이 올바른지 테스트하고 싶었던 마지막 시간을 기억할 수 없으므로 사용 사례에 대해 조금 더 많은 정보를 제공하면 다른 방법으로 문제를 해결할 수 있습니다.
Stefan

@Stefan 간단히 말해서, 재귀 맵 카를 구현하고 싶습니다. 주어진 목록의 요소, 목록의 요소 요소, 목록의 요소 요소 등에서 주어진 기능을 평가합니다. 따라서 요소가 실제 목록인지 아닌지를 알아야합니다.
tom

예를 들어 html을 구문 분석 libxml-parse-html-region하고 모든 <td>태그 를 추출하려고 할 때 유용 합니다.
tom

적절한 목록이나 부적절한 목록 또는 다른 것을 얻을 수 있고 세 가지 경우를 다르게 처리해야하는 구체적인 예를 보여 주실 수 있습니까? 내가 다루어야 할 대부분의 경우, "적절한"사례와 "적절한"사례는 실제 부적절한 꼬리에 도달 할 때까지 공유 될 수 있으므로 그것이 적절한 지 여부를 다시 테스트 할 필요가 없습니다. 그건 consp대신.
Stefan

1
libxml은 목록 목록 만 반환하지 않습니다. XML 요소를 나타내는 각 목록은 양식 (기호 속성. 내용)을 갖습니다. 따라서 코드는 목록의 모든 요소에 맵 카를 반복적으로 적용하지 말아야 cddr합니다 (요소 이름과 속성을 건너 뛰기 위해). 그렇게하면 모든 목록이 올 바르고 문제가 사라질 것입니다. 또한 요소 의 td속성을 혼동 할 수있는 코드의 버그를 수정합니다 td.
Stefan

답변:


22

그것을 만족 시키므로 listp, 그런 의미에서 목록입니다. listp단지 무언가가 단점인지 아니면 nil(일명 ()) 다른 한편으로 무언가인지 테스트합니다 .

적절한 목록 또는 진정한 목록 (점선 목록 또는 원형 목록이 아니거나 목록)입니다 무언가이다 listp, 또한이 nil마지막 지휘관으로. 즉 목록입니다 XS입니다 적절한 경우 (cdr (last XS))이다 nil(그리고 당신이 그것을 구별하는 방법이다).

이것을 넣는 또 다른 방법 은 올바른 목록에 cdr과 같은 적절한 목록 이 있다는 입니다. 데이터 유형 (적절한) 목록 이 유형화 된 언어로 정의되는 방식입니다. 일반적이고 재귀 적 유형 정의입니다. 일반적인 부분은 비어 있지 않은 목록 생성자 (종종 cons, BTW)에 대한 첫 번째 인수 는 모든 유형이 될 수 있다고 말합니다 . 재귀 부분은 두 번째 인수가 (적절한) List 유형의 인스턴스라고 말합니다 .

예, 당신은 주어진이 있는지 여부를 확인 listp하여 적절한 목록 (cdr (last XS))이다가 nil. 동물의 cdr 자체가 올바른 목록인지 확인하려면 cdr이 마지막 단점 인 끝까지 계속 확인해야합니다 nil. 원하는 경우 다음과 같이 술어를 정의 할 수 있습니다.

(defun true-listp (object)
  "Return non-`nil' if OBJECT is a true list."
  (and (listp object)  (null (cdr (last object)))))

순환 목록은 끝이 없지만 Emacs (Emacs 24로 시작)는 last올바르게 검사하기에 충분히 영리하므로이 코드는 순환 목록에서도 작동하지만 Emacs 24.1 이상에서만 작동합니다. 이전 버전의 경우 "무한"재귀를 얻습니다. 스택 오버플로까지).

length적절한 목록 및 기타 시퀀스에서만 기능을 사용할 수 있습니다 . function도 참조하십시오 safe-length.

Elisp 매뉴얼, 노드 Cons 셀을 참조하십시오 .

표기법 (a b)은 구문 설탕입니다 (a . (b . nil))-Elisp 매뉴얼 노드 점 쌍 표기법을 참조하십시오


올바른 목록을 확인하는 가장 좋은 방법은 무엇입니까? 경우 검사 (cdr (last XS))것은 nilcrumblesome입니다. 같은 기능이 proper-list-p없습니까?
tom

@tom : 저것 또는 이와 동등한 것이 필요합니다-마지막 죄수 셀을 확인해야합니다. 이에 대한 답변을 지금 추가했습니다.
Drew

I가 함수의 본문을 바꿀 것 @ 드류 (unless (atom x) (not (cdr (last x))))그래서 당신도 호출 할 수 있습니다 (true-list-p "text")얻을 nil오류가 없습니다.
tom

@tom : 맞다; 고마워. 실제로, 그것이 단점인지 nil(즉, listp) 확인하기 위해 먼저 테스트해야합니다 . (또한, FWIW, 내가 사용하지 않는 unlesswhen자신의 반환 값의 내가 사용합니다. and, or그리고 if그것을 위해.)
드류
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.