スポンサーサイト

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

F#入門第21回(リストを引数にとる関数(4)とoption型とmatch式(1))

今回のお題は「リストを引数にとる関数(4)とoption型とmatch式(1)」です。
 
まずは宿題の答えです。
色々な型のものを,文字列に直すmy_any_to_stringという関数(引数一つ)を定義してください。(ヒント sprintfを使ってください。)
 
(答え)
 
let my_any_to_string a =
    sprintf "%A" a
 
さて今日の話題です。
前にList.filterという関数を紹介しました。
例えば
 
> List.filter (fun x -> x % 2 = 0) [1;2;3;4;5];;
val it : int list = [2; 4]
 
> List.filter (fun x -> x % 2 = 0) [1;3;5];;
val it : int list = []
 
というように,trueかfalseを返す関数と、リストを引数として、リストの要素に関数を適用して、trueを返す要素だけを集めてリスト化したものを返す関数でした。
さてここで、trueを返す要素全部ではなく、trueを返す最初の要素を返す関数を考えたいと思います。(List.tryfindという名の関数です。)この場合、trueを返す要素があれば、それを返せばよいのですが、まったくtrueを返す要素がない場合があります。
このような場合はどのような値を返せばよいのでしょうか。
F#のとった解答は、「値がない場合はNoneを返す、ある場合は、その値をSomeで包んで、Some(値)という形で返す」というものです。
このように、Some(値)とNoneの二つの型がある型をoption型といいます。
それではList.tryfindの型を見てみます。
 
> List.tryFind;;
val it : (('a -> bool) -> 'a list -> 'a option) = <fun:clo@0-7>
 
実行例
 
> List.tryFind (fun x -> x % 2 = 0) [1;2;3;4;5];;
val it : int option = Some 2
 
> List.tryFind (fun x -> x % 2 = 0) [1;3;5];;
val it : int option = None
 
Some (2) などの値が返ってきた場合,どうすれば2だけを取り出せるのでしょうか?
答えはパターンマッチです。
 

 
let (Some (k)) = Some (2);;
val k : int = 2 //警告がでますが、ここでは気にしないでください。
 
一般にoption型の値を得た場合、「Some(値)の形の場合は、こう処理する、Noneの時は、こう処理する」と場合分けをして処理していく必要があります。これまでに、場合分けに使ってきたのはif 式でしたが、もうひとつF#には、強力な場合分けの手段が提供されています。それがmatch式です。
 
match式は非常に応用範囲が広いのですが、基本的な形は次のようになります。
 
match 式 with
|rule1 -> 値1
|rule2 -> 値2
 ...
|rule? -> 値?
 
式を上からruleを満たすかどうかを試していき、ruleを満たしたところで、それに対応する値を返します。上の式全体で一つの値を返す式です。
if 式と同様に返る可能性のある値の型は同じでなければなりません。
ruleの書き方はたくさんあるのですが、まずはパターンマッチを紹介します。
option型でいえば、Some(k)の形とNoneの形にマッチする二つの場合が考えられます。
それでは、'a option型を引数にとり、Some(k)の形なら、その値を表示し、Noneであれば、“None"と表示する関数optionDispをmatch式を利用して定義してみます。
 
let  optionDisp x  =
    match x with
    | Some(k) -> printfn "%Aだよ" k
    | None     -> printfn "None"
 
実行例    
 
> optionDisp (Some(4));;
4だよ
val it : unit = ()
 
> optionDisp (None);;
None
val it : unit = ()
 
上の例から分かるように、xとSome(k)のパターンが一致したときには,let Some(k) = x の形で、kが束縛されます。
パターンマッチと、新しい識別子の導入ならびに、束縛が一気に行われるのです。
 
さらにrule部分にはwhen guardsというものを、付け加えることができます。次の例を見てください。
 
let  optionDisp x  =
    match x with
    | Some(k) when k > 0 -> printfn "正の数%dだよ" k
    | Some(k) when k = 0 -> printfn "0だよ" 
    | Some(k)            -> printfn "負の数%dだよ" k
    | None     -> printfn "None"
 
この例では、Some(k)とパターンマッチが試みられたあと、さらにwhenのあとの条件を満たさないと、値を返すことができません。
 
最後にワイルドカード_を紹介します。これは何にでもマッチします。
またマッチが行われるとき識別子の導入、束縛が行われません。
大きく次の二つの用途で、使われることが多いようです。
 
(1) 場合分けで残りの場合を全部ひとまとめにする。
 
(2) パターンマッチはしたいけど、使う予定のない識別子を導入したくない。
 
(1)の例
 
let  optionDisp x  =
    match x with
    | Some(k) when k > 0 -> printfn "正の数%dだよ" k
    | Some(k)            -> printfn "負の数%dだよ" k
    | _                  -> printfn "正でも負でもないよ"
    
 
(2) の例
 
let  optionDisp x  =
    match x with
    | Some(_)  -> printfn "値があるよ" 
    | None     -> printfn "値はないよ"
    
 
それでは宿題です。
リストと数 kを引数にして、リスト内でkより大きい最初の要素eを探して、見つかれば”見つかりました。kより大きい最初の要素はeです”と表示し、見つからなければ”kより大きい要素は見つかりませんでした”と表示する関数dispFirstMoreThanを定義してください。(List.tryFindとmatch式を使用してください。)
スポンサーサイト

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

コメントの投稿

非公開コメント

こんにちは

let x = Some 2 //括弧はなくてもいいです
のような、Some だと(Noneではないと)分かっている場合には、
x.Value
のように値を取り出すことが出来ます。
なので、例えば
let optionDisp (x:'a option) = if x.IsSome then printfn "%Aだよ" x.Value else printfn "None"
のように書けます。

コメントありがとうございます

勉強になります。ありがとうございます。またよろしかったら御指導くだせいませ。
プロフィール

T GYOUTEN

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

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

この人とブロともになる

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