bgnori / broom

golang practice.
1 stars 0 forks source link

=, eq, eqvの整理. #22

Closed bgnori closed 10 years ago

bgnori commented 10 years ago
bgnori commented 10 years ago

Scheme

述語, 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? 
bgnori commented 10 years ago

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
bgnori commented 10 years ago

reflect.DeepEqualをmapに対して使うとどうなるのだろう? メモリパターン的に同じであるかを見るのかkey/valueの集合比較なのか.

bgnori commented 10 years ago

マップリテラル, Island Life

つまり、ハッシュ関数と比較関数が言語で決め打ちになっていれば (たとえカスタマイズできるとしても、
大部分のケースをカバーできる関数がデフォルトに なっていれば)、言語としてリテラルを決めてしまって
もいい。 マップリテラルがある他の言語は、そういうことだ。 ハッシュ/比較関数の自由度と、リテラルの
便利さがトレードオフになっているわけだ。 

Lispには比較関数がいくつもあって、これはプログラマの 選択肢をできるだけ用意しとくって精神なんだ
ろうけど、敢えてデフォルトに 絞り込もうとすると「eqかeql」とequalp (Schemeなら「eq?かeqv?」と
equal?) が考えられる。 この二つは甲乙つけがたい。基本的に、前者はオブジェクトとしての同一性、 
後者は値としての同一性を見ていると考えられるけど、 どちらも同じくらい必要なことが多いからだ。 

ところでClojureはマップリテラルを持っている。 その理由は、Clojureではオブジェクトの同一性よりも
値の同一性の方が はるかに重要なので、比較関数を = に決め打ちしてしまってもほぼ問題にならない
から。 で、なぜ値の同一性の方がそんなに重要になるかというと、 Clojureのデータ構造が原則
immutableだから。 immutableなデータ構造では、値の同一性のみが問題になる (メモリ上の同
一番地にあろうが別の場所にあろうが、それらのオブジェクトは 操作に対してまったく同様に振る舞う
ので、区別できない)。

だもんでClojureに関して言えば、データ構造のmutabilityを捨てたら マップリテラルが自然についてきた、
という感じだ。

マップリテラルがあるかどうかには、 「等しい」とは何か、という問いが隠されている、という話。 
俺言語を設計するときにでも参考にされたし。 
bgnori commented 10 years ago

Scheme vs. Common Lisp ホントに名前違いだけなの?

bgnori commented 10 years ago

go maps in action

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!

Comparison operators, go spec

ざっくり値として等しいかどうか考えるらしい. mapの等しさについては何も言っていない. たぶん比較不能.

bgnori commented 10 years ago
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}))
}

play groundで実行

bgnori commented 10 years ago

reflect.DeepEqualを追加してみた. 関数名はequalにするのが相当だと思われる. play groundで実行

bgnori commented 10 years ago

Symbolの実装も要注意. allocして辞書に登録, 返すのは登録したobjectということになる. 要は x == y のeqで意図した動作をするようにする.

bgnori commented 10 years ago

現状の実装としては, object.goでEqが定義され, builtinの=として提供されている. eq, equalは存在しない. tests, broom/*では数値の比較等, すべて=で書かれている模様.

bgnori commented 10 years ago

7a2e9fa056dad8aeedb4c5aa47d0b91877d886c1