Closed bgnori closed 10 years ago
Scheme
eq?,eqv?,equal?では,等しいと判定される判断基準が異なる.
eq?は,比較する2つの引数がシステム内部で同一のデータ(セル)を指し示している場合に#tを返す.
eqv?は,eq?で等しいか数値として等しい2つの引数が与えられたとき#tを返す.
equal?は,評価した結果が等しいような2つの引数が与えられたとき#tを返す.
eq?で等しいと判定されるデータは,eqv?,equal?でも等しい.
eqv?で等しいと判定されるデータは,equal?でも等しい.
equal?で等しいと判定されるデータがeqv?,eq?で等しいとは限らない.
eqv?で等しいと判定されるデータがeq?で等しいとは限らない.
equal?は汎用的.eq?は高速.
直観的には,
symbolの比較には,eq?
symbolと数値を同時に扱う場合は,eqv?(数値のみを扱う場合は,"="の方がよい)
listの構造の比較には,equal?
What is the difference between eq?, eqv?, equal?, and = in Scheme?, stackoverflow
=は数字
(= 2 3) => #f
(= 2.5 2.5) => #t
(= '() '()) => error
eq?はポインタ比較
(define x '(2 3))
(define y '(2 3))
(eq? x y) => #f
symbolがinternされているとかその辺を考慮すること.
eqv?は値比較.
(eqv? 2 2) => #t
(eqv? "a" "a") => #t
equal?は再帰的比較
(define x '(2 3))
(define y '(2 3))
(equal? x y) => #t
(eqv? x y) => #f
reflect.DeepEqualをmapに対して使うとどうなるのだろう? メモリパターン的に同じであるかを見るのかkey/valueの集合比較なのか.
つまり、ハッシュ関数と比較関数が言語で決め打ちになっていれば (たとえカスタマイズできるとしても、
大部分のケースをカバーできる関数がデフォルトに なっていれば)、言語としてリテラルを決めてしまって
もいい。 マップリテラルがある他の言語は、そういうことだ。 ハッシュ/比較関数の自由度と、リテラルの
便利さがトレードオフになっているわけだ。
Lispには比較関数がいくつもあって、これはプログラマの 選択肢をできるだけ用意しとくって精神なんだ
ろうけど、敢えてデフォルトに 絞り込もうとすると「eqかeql」とequalp (Schemeなら「eq?かeqv?」と
equal?) が考えられる。 この二つは甲乙つけがたい。基本的に、前者はオブジェクトとしての同一性、
後者は値としての同一性を見ていると考えられるけど、 どちらも同じくらい必要なことが多いからだ。
ところでClojureはマップリテラルを持っている。 その理由は、Clojureではオブジェクトの同一性よりも
値の同一性の方が はるかに重要なので、比較関数を = に決め打ちしてしまってもほぼ問題にならない
から。 で、なぜ値の同一性の方がそんなに重要になるかというと、 Clojureのデータ構造が原則
immutableだから。 immutableなデータ構造では、値の同一性のみが問題になる (メモリ上の同
一番地にあろうが別の場所にあろうが、それらのオブジェクトは 操作に対してまったく同様に振る舞う
ので、区別できない)。
だもんでClojureに関して言えば、データ構造のmutabilityを捨てたら マップリテラルが自然についてきた、
という感じだ。
マップリテラルがあるかどうかには、 「等しい」とは何か、という問いが隠されている、という話。
俺言語を設計するときにでも参考にされたし。
Scheme vs. Common Lisp ホントに名前違いだけなの?
A Go map type looks like this:
map[KeyType]ValueType
where KeyType may be any type that is comparable (more on this later), and ValueType may be any type at all, including another map!
ざっくり値として等しいかどうか考えるらしい. mapの等しさについては何も言っていない. たぶん比較不能.
eq(x, y interface{}) bool {
return x == y
}
をeqの実装にすることが自然に思える.
package main
import "fmt"
func eq(x, y interface{}) bool {
return x == y
}
type Foo struct {
dummy int
}
func main() {
fmt.Println(eq("a", "a"))
fmt.Println(eq(1, 1))
fmt.Println(eq(nil, nil))
fmt.Println(eq(&Foo{dummy: 1}, &Foo{dummy: 1}))
}
reflect.DeepEqualを追加してみた. 関数名はequalにするのが相当だと思われる. play groundで実行
Symbolの実装も要注意. allocして辞書に登録, 返すのは登録したobjectということになる. 要は x == y のeqで意図した動作をするようにする.
現状の実装としては, object.goでEqが定義され, builtinの=として提供されている. eq, equalは存在しない. tests, broom/*では数値の比較等, すべて=で書かれている模様.
7a2e9fa056dad8aeedb4c5aa47d0b91877d886c1