スポンサーサイト

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

F#入門第23回(Discriminated union(1))

今回のお題は「Discriminated union(1)」です。
 
まずは宿題の答えです。
 
(宿題)
リストと数 kを引数にして、リスト内でkより大きい最初の要素eを探して、見つかれば”見つかりました。kより大きい最初の要素はeです”と表示し、見つからなければ”kより大きい要素は見つかりませんでした”と表示する関数dispFirstMoreThan2を定義してください。(List.filterとmatch式を使用してください。)
 
(宿題の答え)
 
let dispFirstMoreThan2 k lst =
    let chosen = List.filter (fun x -> x > k) lst
    match chosen with
    | hd::tl  -> printfn "見つかりました。%Aより大きい最初の要素は%Aです" k hd
    | []      -> printfn "%Aより大きい要素は見つかりませんでした" k
 
実行例
 
> dispFirstMoreThan2 1.5 [1.0;0.1;2.8;6.0];;
見つかりました。1.5より大きい最初の要素は2.8です
val it : unit = ()
 
> dispFirstMoreThan2 9.0 [1.0;0.1;2.8;6.0];;
9.0より大きい要素は見つかりませんでした
val it : unit = ()
 
さて、それでは今回の話ですが、まずはoption型を思い出してください。
これは、大雑把にいうと「ある」か「ない」か型で、「ある」の方は値を保持できるのでした。
 
これを、一般化して、自分で定義するのが Discriminated union 型になります。
つまり、対象を大きく何通りかに分けて、それぞれの場合について値を保持する必要があるのであれば、それを付加することができます。
 
それではまず自分定義のtrue,falseをmyBool型として定義してみます。
(これは対象を2通りに分けて、どちらも値を保持しない場合の例です。)
 
> type MyBool =
    | MyTrue
    | MyFalse;;
 
type MyBool =
  | MyTrue
  | MyFalse
 
myBool型を引数にとって、MyTrueかMyFalseかを表示する関数myBoolDispを定義してみます。
 
let myBoolDisp x =
    match x with
    | MyTrue  -> printfn "私専用のtrue"
    | MyFalse -> printfn "私専用のfalse"  ;;
 
val myBoolDisp : MyBool -> unit
 
結構すごいのは、パターンマッチの候補から、引数の型を型推論してくれているところです。ただ、曖昧性がでて、型推論が効かないときはxの後ろに型注釈をいれて(x : myBool)のようにしましょう
 
実行例
 
> myBoolDisp MyTrue;;
私専用のtrue
val it : unit = ()
 
myBoolDispはいわば、MyBool型に専門化された関数ですから、型定義の外で、定義するより、内部で定義しておくのが普通です。
例えばmyBoolDisp をdispと命名しなおして、定義すると次のようになります。
 
定義
 
type MyBool =
    | MyTrue
    | MyFalse
    
    member this.disp =
        match this with
        | MyTrue  -> printfn "私専用のtrue"
        | MyFalse -> printfn "私専用のfalse" 
        
F#Interactiveから返される型
 
type MyBool =
  | MyTrue
  | MyFalse
  with
    member disp : unit
  end
 
キーワードmemberとthisを使います。
member this.関数名とし、この部分の下には、MyBool型の引数がthisという名前で与えられているという想定のもとで、コードを書けばよいことになります。
 
普通の関数の呼び出す方法は、「関数 引数 」ですが、この場合は「引数.関数」です。(さらに外部からの引数がある場合は、「引数.関数 その他の引数」 となります。
 
実行例
 
> MyTrue.disp;;
私専用のtrue
val it : unit = ()
 
 
つぎにint option型のようなもの、を自分で定義してみます。
名前をMyIntOptionとします。
(これは対象を2通りに分けて、片方だけ値を保持する場合の例です。)
 
type MyIntOption =
    | MySomeInt of int
    | MyNoneInt 
 
値を保持する方にはofキーワードをつけて、そのあとに保持する値の型を書きます。
値を保持する方は次のような形で使えます。
 
> MySomeInt (3);;
val it : MyIntOption = MySomeInt 3
 
それでは、MyIntOption型の値と、int型の値を引数にして、足せれば和を表示し、足せなければ”足せません”と表示する関数を、型定義の外部で定義してみます。
 
let sumDisp x y =
    match x with
    | MySomeInt (v) -> printfn "和は%dです" (v + y)
    | MyNoneInt     -> printfn "足せません" 
    

val sumDisp : MyIntOption -> int -> unit
実行例
 
> sumDisp (MySomeInt (3)) 9;;
和は12です
val it : unit = ()
 
> sumDisp MyNoneInt 9;;
足せません
val it : unit = ()
 
さて、こんどは、この関数を内部定義してみます。
 
定義
 
type MyIntOption =
    | MySomeInt of int
    | MyNoneInt  
    
    member this.sumDisp  y =
        match this with
        | MySomeInt (v) -> printfn "和は%dです" (v + y)
        | MyNoneInt     -> printfn "足せません" 
 
 F#Interactiveから返される型
 
 type MyIntOption =
  | MySomeInt of int
  | MyNoneInt
  with
    member sumDisp : y:int -> unit
  end
  
実行例
 
> (MySomeInt (3)).sumDisp 9;;
和は12です
val it : unit = ()
 
> MyNoneInt.sumDisp 9;;
足せません
val it : unit = ()
 
宿題
 
上と同様にして、MyFloatOptionを定義してみてください。
その際、sumDispの代わりに、divDisp(割り算結果を表示する関数)を内部で定義してください。
ただし、値がない場合か、割ろうとする引数が0.0のときは、”割れません”と表示するようにしてください。
スポンサーサイト

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

コメントの投稿

非公開コメント

this

メンバーとしてオブジェクト自身を表す this は、
識別できれば this でなくても
self でもなんでもOKです。

this or self or ?

このような場合はthis派とself派とその他派に分かれるかと思うのですが、なんでもOKという仕様は、「どの言語から流れてきても、好きなのを使ってください」というノリなのでしょうか。個人的には何かに統一するという制限を加えてくれた方が分かりやすい気がします。

ノリ

>…というノリなのでしょうか
言語デザインした人に訊いてみないと本当のところは分かりませんが、
member this.sumDisp …
のように書いた場合には、そのオブジェクトのメンバーについて書いているのが明らかであって、
ここで書いた名前が、その内側で使われるんだから(つまりバインド的な?)
なんでもいいんじゃね?
的なノリなのかもしれませんね。

私的には、最初にオブジェクト指向を学んだのはSmalltalk だったので、self が好みですが、
どうでもいいような、テストコードを書いている時には、単にx だったりします。

そういえば、CLOS (Common Lisp) のような言語も、
メソッド定義でのオブジェクト自身というのは、単なるメソッドの引数のように扱われるので、特別な名前(予約語やキーワードみたいな)が使われないですね。
プロフィール

T GYOUTEN

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

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

この人とブロともになる

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