Scheme에서 eq ?, eqv ?, equal ?, =의 차이점은 무엇입니까?


85

Scheme에서 이러한 작업의 차이점이 무엇인지 궁금합니다. Stack Overflow에서 비슷한 질문을 보았지만 Lisp에 관한 질문이며 세 연산자 사이에 비교가 없습니다.

Scheme에서 다양한 유형의 명령을 작성하고 있는데 다음과 같은 출력이 나타납니다.

(eq? 5 5) -->#t
(eq? 2.5 2.5) -->#f
(equal? 2.5 2.5) --> #t
(= 2.5 2.5) --> #t

왜 그렇습니까?


3
또한 거기에 eqv?있는이에서 뭔가 다른 의미, eq?또는equal?
newacct

답변:


155

이 질문에 점진적으로 대답하겠습니다. =동등성 술어 부터 시작하겠습니다 . =조건은 두 개의 번호가 동일한 지 여부를 확인하는 데 사용됩니다. 숫자가 아닌 다른 값을 제공하면 오류가 발생합니다.

(= 2 3)     => #f
(= 2.5 2.5) => #t
(= '() '()) => error

eq?술어는 두 개의 파라미터 메모리에 동일한 객체를 respresent 여부를 확인하는데 사용된다. 예를 들면 :

(define x '(2 3))
(define y '(2 3))
(eq? x y)         => #f
(define y x)
(eq? x y)         => #t

그러나 '()메모리에는 빈 목록이 하나뿐입니다 (실제로 빈 목록은 메모리에 존재하지 않지만 메모리 위치에 대한 포인터 0는 빈 목록으로 간주됩니다). 따라서 빈 목록 eq?을 비교할 때 항상 반환됩니다 #t(메모리에서 동일한 객체를 나타 내기 때문에).

(define x '())
(define y '())
(eq? x y)      => #t

이제 구현에 따라 숫자, 문자열 등과 같은 기본 값에 대해 eq?반환하거나 반환하지 않을 수 있습니다 #t. 예를 들면 다음과 같습니다.

(eq? 2 2)     => depends upon the implementation
(eq? "a" "a") => depends upon the implementation

이것이 eqv?술어가 등장하는 곳 입니다. 은 eqv?정확히 동일하다 eq?항상 반환하는 것을 제외하고, 조건 #t같은 원시 값. 예를 들면 :

(eqv? 2 2)     => #t
(eqv? "a" "a") => depends upon the implementation

따라서 eqv?의 상위 집합입니다 eq?당신이 사용해야하는 대부분의 경우 eqv?대신은 eq?.

마지막으로 equal?술어에 도달합니다 . equal?술어는 정확히 동일하다 eqv?또한 두 그룹, 벡터 등이 만족 요소 대응 여부를 테스트하는데 사용될 수 있다는 것을 제외하고는, 술어 eqv?술어. 예를 들면 :

(define x '(2 3))
(define y '(2 3))
(equal? x y)      => #t
(eqv? x y)        => #f

일반적으로 :

  1. =두 숫자가 같은지 테스트 하려면 술어를 사용하십시오 .
  2. eqv?두 개의 숫자가 아닌 값이 동일한 지 여부를 테스트 하려면 술어를 사용하십시오 .
  3. equal?두 목록, 벡터 등이 동일한 지 테스트 하려면 술어를 사용하십시오 .
  4. eq?수행중인 작업을 정확히 알지 못하는 경우 술어를 사용하지 마십시오 .

7
AFAIK (eqv? "a" "a") ==> unspecified. 당신은 사용해야합니다 equal?또는 (가능성이 더 최적화)string=?
Sylwester

3
에 따라 보고서 , (eq? '(1) '(1))이다 지정되지 않은 당신, 그래서 (define x '(1 2))그림이 작동하지 않을 수 있습니다.
윌 네스

4
매우 정확하고 유익합니다. 특히 마지막 가이드 라인.
Germán Diago

2
하지만 EQ? 기호에 대해 정의 된 것으로 보이며주의해야합니다! 기호가 같으면 eq? #t를 반환합니다. 예 (eq? 'foo 'foo) -> #t, (eq? 'foo 'bar)-> false`. 나는이 글을 읽을 여기여기에
Nedko

13

.NET과 관련된 RnRS 사양에는 전체 두 페이지가 eq?, eqv?, equal? and =있습니다. 다음은 R7RS 사양 초안 입니다. 확인 해봐!

설명:

  • = 숫자를 비교하면 2.5와 2.5는 수치 적으로 동일합니다.
  • equal?숫자가으로 감소하면 =2.5와 2.5는 수치 적으로 동일합니다.
  • eq?'포인터'를 비교합니다. Scheme 구현에서 숫자 5는 '즉시'(가능성)로 구현되므로 5와 5는 동일합니다. 숫자 2.5는 Scheme 구현에서 '부동 소수점 레코드'할당이 필요할 수 있지만 두 포인터는 동일하지 않습니다.

1
Draft R7RS 사양에 대한 링크는 2018-02-04
Jeremiah Peschka

2
라이브 링크로 업데이트되었습니다.
GoZoner

10

eq?#t은 동일한 어드레스 / 오브젝트 인 경우. 일반적으로 동일한 기호, 부울 및 객체에 대해 #t를 기대하고 값이 다르거 나 동일한 구조가 아닌 다른 유형의 값에 대해 #f를 기대할 수 있습니다. Scheme / Lisp 구현에는 포인터에 유형을 포함하고 포함하는 전통이 있습니다 충분한 공간이면 같은 공간에 값을 입력합니다. 따라서 일부 포인터는 실제로 주소가 아니지만 char R또는 Fixnum 과 같은 값10 입니다. 다음은 될 것 eq?"주소는"임베디드 형 + 값이 때문이다. 일부 구현에서는 변경 불가능한 상수도 재사용합니다. (eq? '(1 2 3)'(1 2 3))은 해석 될 때 #f 일 수 있지만 동일한 주소를 얻을 수 있으므로 컴파일 할 때 #t 일 수 있습니다. (자바의 상수 문자열 풀처럼). 이 때문에eq? 지정되지 않으므로 #t 또는 #f로 평가되는지 여부는 구현에 따라 다릅니다.

eqv?#t는 eq?. 데이터가 너무 커서 포인터에 맞지 않는 경우에도 숫자 또는 문자이고 값이 동일하면 #t 입니다. 따라서 eqv?해당 유형이 지원되는 유형 중 하나인지, 둘 다 동일한 유형이고 대상 객체의 데이터 값이 동일한 지 확인하는 추가 작업을 수행합니다.

equal?eqv?쌍, 벡터, 문자열 및 바이트 벡터와 같은 복합 유형 인 equal?경우 부분에 대해 재귀 적으로 수행 하는 것과 동일한 일에 대해 #t입니다 . 실제로 두 개체가 동일하게 보이면 #t를 반환합니다 . R6RS 이전에는 equal?원형 구조 에 사용 하는 것이 안전하지 않습니다.

=비슷 eqv?하지만 숫자 유형에 대해서만 작동합니다 . 더 효율적일 수 있습니다.

string=?equal?같지만 문자열에서만 작동합니다. 더 효율적일 수 있습니다.


6

equal? 두 개체 (모든 유형)가 동일한 지 재귀 적으로 비교합니다.

  • 전체 목록, 문자열, 벡터 등을 순회해야하기 때문에 대규모 데이터 구조의 경우 비용이 많이들 수 있습니다.

  • 개체에 단일 요소 (예 : 숫자, 문자 등) 만 포함되어있는 경우 이는 eqv?.


eqv? 두 개체가 "일반적으로 동일한 개체로 간주"되는지 확인하기 위해 두 개체를 테스트합니다.

  • eqv?eq?매우 유사 작업, 그리고 그들 사이의 차이가 어느 정도 구현 구체적 것입니다.

eq?동일 eqv?하지만 더 미세한 구별을 식별 할 수 있으며 더 효율적으로 구현 될 수 있습니다.

  • 사양에 따르면 이것은 .NET에 대한 더 복잡한 작업과 달리 빠르고 효율적인 포인터 비교로 구현 될 수 있습니다 eqv?.


= 숫자가 같은지 비교합니다.

  • 두 개 이상의 숫자를 제공 할 수 있습니다. 예 : (= 1 1.0 1/1 2/2)

나는 eq?실제 포인터 평등 (아님 eqv?) 이라고 생각했습니다 . "가장 훌륭하거나 가장 차별적 인"것입니다. 예 : (eqv? 2 2)는 보장 #t되지만 (eq? 2 2)"지정되지 않음"입니다. 즉, 구현이 새로 읽은 각 번호에 대해 실제 새 메모리 객체를 생성하는지 또는 가능한 경우 이전에 생성 된 메모리 객체를 재사용하는지 여부에 따라 다릅니다.
윌 네스

@WillNess-좋은 캐치, 감사합니다. 사이의 차이 eq?와는 eqv?다른 작업보다 더 미묘하다.
Justin Ethier 2013

5

스키마 구현에 대해서는 언급하지 않았지만 Racket에서는 eq?인수가 동일한 객체를 참조하는 경우에만 true를 반환합니다. 두 번째 예는 시스템이 각 인수에 대해 새로운 부동 소수점 숫자를 생성하기 때문에 #f를 산출하는 것입니다. 그들은 같은 대상이 아닙니다.

equal?=가치 등가 확인되지만, =숫자에만 적용됩니다.

Racket을 사용하는 경우 여기 에서 자세한 정보를 확인 하세요 . 그렇지 않으면 스키마 구현 문서를 확인하십시오.


3
더 나은 방법 ... 사양 읽기 ... r6rs.org/final/html/r6rs/r6rs-ZH-14.html#node_sec_11.5
Dirk

3

eq?포인터 동등성으로 생각하십시오 . 보고서 작성자는 가능한 한 일반적이기를 원하므로 구현에 따라 다르며 포인터 기반 구현을 선호하기 때문에 솔직하게 말하지 않습니다. 그러나 그들은 말한다

일반적으로 eq를 구현할 수 있습니까? 예를 들어 간단한 포인터 비교와 같이 eqv보다 훨씬 효율적입니다.

제가 의미하는 바는 다음과 같습니다. (eqv? 2 2)반환이 보장 #t되지만 (eq? 2 2)지정되지 않았습니다. 이제 포인터 기반 구현을 상상해보십시오. 그것은 eq?단지 포인터 비교입니다. 이후 (eq? 2 2)지정되어 있지 않은,이 구현은 그냥 소스 코드에서 읽고 각각의 새로운 수의 새로운 메모리 개체 표현을 자유롭게 만들 수 있음을 의미합니다. eqv?실제로 인수를 검사해야합니다.

OTOH (eq 'a 'a)#t. 이것은 그러한 구현이 중복 된 이름을 가진 심볼을 인식 하고 그들 모두에 대해 메모리에서 동일한 하나의 표현 객체를 사용해야 함을 의미 합니다.

구현이 포인터 기반이 아니라고 가정합니다. 보고서를 준수하는 한 중요하지 않습니다. 작성자는 구현 자에게 구현의 세부 사항을 지시하는 것으로 보이기를 원하지 않으므로 신중하게 표현을 선택합니다.

어쨌든 이것은 내 추측입니다.

매우 조잡하게 eq?포인터 동등성, eqv?(원자) 값 인식, equal?구조 인식 (재귀 적으로 인수를 확인하므로 최종적 (equal? '(a) '(a))으로이어야 함 #t), =숫자, string=?문자열, 세부 사항은 다음과 같습니다. 보고서에서.


0

이전 답변 외에도 몇 가지 의견을 추가하겠습니다.

이러한 모든 술어 identity는 객체 에 대한 추상 기능을 정의 하지만 컨텍스트는 다릅니다.

EQ?구현에 따라 다르며 are 2 objects the same?제한된 사용에서만 질문에 답하지 않습니다 . 구현 관점에서이 술어는 2 개의 숫자 (개체에 대한 포인터)를 비교하고 개체의 내용을 보지 않습니다. 예를 들어 구현에서 문자열을 내부에 고유하게 유지하지 않고 각 문자열에 대해 다른 메모리를 할당 (eq? "a" "a")하면 false가됩니다.

EQV?-이것은 개체 내부를 보지만 제한적으로 사용됩니다. 에 대해 true를 반환하면 구현에 따라 다릅니다 (eqv? (lambda(x) x) (lambda(x) x)). 제한된 사용으로 일부 함수의 기능을 비교하는 몇 가지 빠른 방법이 있다는 것을 오늘날 알고 있기 때문에이 술어를 정의하는 방법은 여기에 완전한 철학입니다. 그러나 eqv?큰 숫자, 문자열 등에 대한 일관된 답변을 제공합니다.

실제로 이러한 술어 중 일부는 객체의 추상적 인 정의 (수학적)를 사용하는 반면 다른 일부는 객체의 표현 (실제 머신에서 구현되는 방식)을 사용합니다. 정체성의 수학적 정의는 라이프니츠에서 비롯되었으며 다음과 같이 말합니다.

X = Y  iff  for any P, P(X) = P(Y)
X, Y being objects and
P being any property associated with object X and Y.

이상적으로는이 정의를 컴퓨터에서 구현할 수 있지만 결정 불가능 및 / 또는 속도 때문에 문자 그대로 구현되지는 않습니다. 이것이이 정의를 둘러싼 다른 관점에 초점을 맞추기 위해 각각을 시도하는 많은 운영자가있는 이유입니다.

연속성을 위해 정체성의 추상적 인 정의를 상상해보십시오. 함수의 하위 집합 ( sigma-recursive class of functions ) 의 정의를 제공 할 수 있더라도 언어는 어떤 술어도 true 또는 false로 강요하지 않습니다. 그것은 언어의 정의와 구현을 훨씬 더 복잡하게 만들 것입니다.

다른 술어의 컨텍스트는 분석하기가 더 쉽습니다.

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