1.6「元子――構造的平等」

1.6「元子――構造的平等」

2021.5.4

元子のメモ

等号 (==)、そして拡張して不等号 (!=) は構造的です。メモリ内の値の物理的表現や同一性に関係なく、それらの内容が等しい場合は必ず、2 つの値 a と裸の値が等しい、a == b になります。 。

たとえば、文字列 "hello world" と "hello"#"world" は、メモリ内の異なるオブジェクトによって表されている可能性がありますが、同じです。

等価性は、共有型、または変更可能なフィールド、変更可能な配列、非共有関数、またはジェネリック型のコンポーネントを含まない型に対してのみ定義されます。

たとえば、オブジェクトの配列を比較できます。

let a = [ {
    
     x = 10 }, {
    
     x = 20 } ]; 
let b = [ {
    
     x = 10 }, {
    
     x = 20 } ]; 
a == b;

结果:true : Bool

重要なのは、これは 参照による比較ではなく 、値による比較であるということです。

サブタイプ:

等価性ではサブタイプが考慮されるため、 { x = 10 } == { x = 10; となります。y = 20 } は true を返します。

サブタイプに対応するため、異なる型の 2 つの値は、最も具体的な共通のスーパータイプで等しい場合、つまり共通の構造が一致する場合に等しいと見なされます。これが微妙な望ましくない動作につながる可能性がある場合、コンパイラは警告を出します。例: { x = 10 } == { y = 20 } は、2 つの値が空のレコード タイプで比較されるため、true を返します。それが意図されている可能性は低いため、コンパイラはここで警告を発行します。

{
    
     x = 10 } == {
    
     y = 20 };

警告:
stdin:1.1-1.25: warning [M0062], comparing incompatible types
{
    
    x : Nat}
and
{
    
    y : Nat}
at common supertype
{
    
    }

结果:true : Bool

汎用タイプ:

ジェネリック型は共有されるように宣言できないため、等価性は非ジェネリック型に対してのみ使用できます。たとえば、次の式では次の警告が生成されます。

func eq<A>(a : A, b : A) : Bool = a == b;

警告:
stdin:1.35-1.41: warning [M0061], comparing abstract type
A/9
to itself at supertype
Any

结果:func : <A>(A, A) -> Bool

Any 型でこれら 2 つを比較すると、この比較は引数に関係なく true を返すことになるため、期待どおりに機能しません。

コードでこの制限に遭遇した場合は、(a, a) -> Bool 型の比較関数を引数として受け入れ、それを使用して値を比較する必要があります。

リストのメンバーシップテストの例を見てみましょう。この最初の実装は機能しません。

import List "mo:base/List"; 
func contains<A>(element : A, list : List.List<A>) : Bool {
    
     
	switch list {
    
     
		case (?(head, tail)) 
			element == head or contains(element, tail); 
		case null 
			false; 
	}
}; 
assert(not contains(1, ?(0, null)));

警告:
stdin:6.7-6.22: warning [M0061], comparing abstract type
A/44
to itself at supertype
Any
stdin:11.1-11.36: execution error, assertion failure

コンパイラーが Any で型 A を比較しているため、このアサーションはトラップされますが、これは常に true であるため、このバージョンの contains は、リストに少なくとも 1 つの要素がある限り、常に true を返します。

2 番目の実装では、比較関数を明示的に受け入れる方法を示します。

import List "mo:base/List"; 
import Nat "mo:base/Nat"; 
func contains<A>(eqA : (A, A) -> Bool, element : A, list : List.List<A>) : Bool {
    
     
	switch list {
    
     
		case (?(head, tail)) 
			eqA(element, head) or contains(eqA, element, tail); 
		case null 
			false; 
		} 
	}; 
assert(not contains(Nat.equal, 1, ?(0, null)));

结果:() : ()

おすすめ

転載: blog.csdn.net/qq_29810031/article/details/123226671