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
왜 그렇습니까?
답변:
이 질문에 점진적으로 대답하겠습니다. =
동등성 술어 부터 시작하겠습니다 . =
조건은 두 개의 번호가 동일한 지 여부를 확인하는 데 사용됩니다. 숫자가 아닌 다른 값을 제공하면 오류가 발생합니다.
(= 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
일반적으로 :
=
두 숫자가 같은지 테스트 하려면 술어를 사용하십시오 .eqv?
두 개의 숫자가 아닌 값이 동일한 지 여부를 테스트 하려면 술어를 사용하십시오 .equal?
두 목록, 벡터 등이 동일한 지 테스트 하려면 술어를 사용하십시오 .eq?
수행중인 작업을 정확히 알지 못하는 경우 술어를 사용하지 마십시오 .(eqv? "a" "a") ==> unspecified
. 당신은 사용해야합니다 equal?
또는 (가능성이 더 최적화)string=?
.NET과 관련된 RnRS 사양에는 전체 두 페이지가 eq?, eqv?, equal? and =
있습니다. 다음은 R7RS 사양 초안 입니다. 확인 해봐!
설명:
=
숫자를 비교하면 2.5와 2.5는 수치 적으로 동일합니다.equal?
숫자가으로 감소하면 =
2.5와 2.5는 수치 적으로 동일합니다.eq?
'포인터'를 비교합니다. Scheme 구현에서 숫자 5는 '즉시'(가능성)로 구현되므로 5와 5는 동일합니다. 숫자 2.5는 Scheme 구현에서 '부동 소수점 레코드'할당이 필요할 수 있지만 두 포인터는 동일하지 않습니다.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?
같지만 문자열에서만 작동합니다. 더 효율적일 수 있습니다.
equal?
두 개체 (모든 유형)가 동일한 지 재귀 적으로 비교합니다.
전체 목록, 문자열, 벡터 등을 순회해야하기 때문에 대규모 데이터 구조의 경우 비용이 많이들 수 있습니다.
개체에 단일 요소 (예 : 숫자, 문자 등) 만 포함되어있는 경우 이는 eqv?
.
eqv?
두 개체가 "일반적으로 동일한 개체로 간주"되는지 확인하기 위해 두 개체를 테스트합니다.
eqv?
과 eq?
매우 유사 작업, 그리고 그들 사이의 차이가 어느 정도 구현 구체적 것입니다.eq?
동일 eqv?
하지만 더 미세한 구별을 식별 할 수 있으며 더 효율적으로 구현 될 수 있습니다.
eqv?
.=
숫자가 같은지 비교합니다.
(= 1 1.0 1/1 2/2)
eq?
실제 포인터 평등 (아님 eqv?
) 이라고 생각했습니다 . "가장 훌륭하거나 가장 차별적 인"것입니다. 예 : (eqv? 2 2)
는 보장 #t
되지만 (eq? 2 2)
"지정되지 않음"입니다. 즉, 구현이 새로 읽은 각 번호에 대해 실제 새 메모리 객체를 생성하는지 또는 가능한 경우 이전에 생성 된 메모리 객체를 재사용하는지 여부에 따라 다릅니다.
eq?
와는 eqv?
다른 작업보다 더 미묘하다.
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=?
문자열, 세부 사항은 다음과 같습니다. 보고서에서.
이전 답변 외에도 몇 가지 의견을 추가하겠습니다.
이러한 모든 술어 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로 강요하지 않습니다. 그것은 언어의 정의와 구현을 훨씬 더 복잡하게 만들 것입니다.
다른 술어의 컨텍스트는 분석하기가 더 쉽습니다.
eqv?
있는이에서 뭔가 다른 의미,eq?
또는equal?