スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門基本編落穂拾い その38 制約(2) comparison 

次の関数定義をみてください。
 
> let isMoreThan x  y =
    x > y;;
 
val isMoreThan : 'a -> 'a -> bool when 'a : comparison
 
今回は制約として「comparisonが定義されていること」と表示されました。
 
 
F#の比較可能な型を要素とする基本的型(タプル、リスト、オプション、レコード、discriminated union)は比較可能になっており、次のような 関数(演算子)が使用可能です。
 
> compare;;
val it : ('a -> 'a -> int) when 'a : comparison = <fun:it@6>
> (<);;
val it : ('a -> 'a -> bool) when 'a : comparison = <fun:it@8-2>
> (<=);;
val it : ('a -> 'a -> bool) when 'a : comparison = <fun:it@9-3>
> (>);;
val it : ('a -> 'a -> bool) when 'a : comparison = <fun:it@10-4>
> (>=);;
val it : ('a -> 'a -> bool) when 'a : comparison = <fun:it@11-5>
> (min);;
val it : ('a -> 'a -> 'a) when 'a : comparison = <fun:it@12-6>
> (max);;
val it : ('a -> 'a -> 'a) when 'a : comparison = <fun:it@13-7>
 
(使用例)
> compare 3 2;;
val it : int = 1     //第一引数が第二引数より大きいとき 1
> compare 3 3;;  
val it : int = 0     //第一引数が第二引数と等しいとき 0
> compare 1 3;;
val it : int = -1   //第一引数が第二引数より小さいとき -1
 
関数(演算子)の中で中心となるのはcompareであり、compareを利用して残りの関数(演算子)は定義されています。
とりあえず、使用可能な演算子をいくつか使ってみます。
 
> max 3 1;;
val it : int = 3
 
ここでリストの大小について調べてみます。
 
> [2;2] > [1;4];;
val it : bool = true
 
> [3]>[1;3];;
val it : bool = true
 
ということで、第一成分を比較して等しければ第二成分を比較してという感じになっているようです。
タプルについても同様のようです。
 
オプション型についてはSome(_)はNoneより大きいとして、Some(x)とSome(y)はxとyの比較になるようです。
 

> Some(3) > Some(2);;
val it : bool = true
> Some (3) > None;;
val it : bool = true
 
次はレコード型です。
 

type Examp = 
    {   fld1 : int ;
        fld2 : int
        } 
 
とすると
 
> {fld1 = 3; fld2 = 0} > {fld1 = 1 ;fld2 = 7};;
val it : bool = true
 
type Examp = 
    {   fld2 : int ;
        fld1 : int
        } 
 
とすると
 
> {fld1 = 3; fld2 = 0} > {fld1 = 1 ;fld2 = 7};;
val it : bool = false
 
ですから、定義が先のフィールドから順に比較されるようです。
 
次はdiscriminated unionです。
 
type Examp =
    |TypeA of int
    |TypeB of int
 
としておいて
 
> (TypeA (0)) > (TypeA (3));;
val it : bool = false
 
で、同じタイプは保持する値の比較となります。
 
> (TypeA (0)) > (TypeB (3));;
val it : bool = false
 
type Examp =
    |TypeB of int
    |TypeA of int
と定義すると
 
> (TypeA (0)) > (TypeB (3));;
val it : bool = true
> (TypeA (5)) > (TypeB (3));;
val it : bool = true
 
ということで、どうも定義が後の部分の方が大きく評価されるよう?です。
(これらの大小関係は、表示の順番を決めるというような場合にはそれなりに並ぶので便利ですが、これらの大小関係に依存したアルゴリズムを書くのは危険かと思われます。)
 
IComparableを実装しておけば、そのクラスはcomparisonとなり上記の演算子が使用可能となります。
 

 
type MyClass (x:int) =
    let _prop1 = 
        if x % 3 = 0   then 
            100*x
        elif x % 3 = 1 then 
            10 * x
        else
            x
    member this.Val =
        _prop1
    interface System.IComparable with
        member this.CompareTo obj =
            this.Val.CompareTo((obj :?> MyClass).Val)  //int型のCompareToを利用
 
 
> let t0 = MyClass (3);;
val t0 : MyClass
 
> let t1 = MyClass (5);;
val t1 : MyClass
 
> t0.Val;;
val it : int = 300
 
> t1.Val;;
val it : int = 5
 
> t0 > t1 ;;
val it : bool = true //内部に保持する_propの値で比較される
 
> compare t0 t1 ;;
val it : int = 1  //compareも使用可能となる
 
よって、このクラスのインスタンスを要素とするリスト等も比較可能となります。
 
> let t2 = MyClass (6);;
val t2 : MyClass
 
> t2.Val;;
val it : int = 600
 
> [t0;t1] < [t2];;
val it : bool = true
 
なお上のクラス定義では
warning FS0343: The type 'MyClass' implements 'System.IComparable' explicitly but provides no corresponding override for 'Object.Equals'. An implementation of 'Object.Equals' has been automatically provided, implemented via 'System.IComparable'. Consider implementing the override 'Object.Equals' explicitly
 
と警告がでますが、最後のObject.Equalsについては、前回紹介した通りで、CompareToとEqualsは矛盾しないように定義しないとCompareToをつかう文脈ではA<BなのにEqualsが使われる文脈ではA=Bとなるという変な事態が発生します。
 
 
(注意)関数も組み込みの型ではありますが安全に比較することができません。
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。