fc2ブログ

F#文法リファレンス - パターンマッチ

概要
 変数のパターンを判別し、適切な値を返します。C系言語のswitch文と似ています。

使用に適した状況
 変数値に応じて何らかの値を返したい場合。条件に応じて処理の流れを変えたい場合。

サンプル

let IsNegative x = if x < 0 then true else false

//単純なパターンマッチ
let NumberShow x = 
  match IsNegative x with
  | true -> printfn "指定された値はマイナスです。"
  | false -> printfn "指定された値はプラスです。"

//パターンマッチを試す
NumberShow -10
NumberShow 10


文法
 「match」キーワード、「対象」、「with」キーワード、| 値-> 戻り値の形式で書きます。「|」(縦棒)記号に続いて一致するパターンと返す値を、想定しているパターンの数だけ書きます。

解説
 変数値に基づいて適切な値を返すのは、関数型プログラミングの基本です。もし、変数値を判定する手段がなければ、プログラミングできません。そんな関数型プログラミングの基本機能ですが、結構複雑です。
 今回紹介したのは一番単純なパターンマッチです。C系言語のswitch文(多岐分岐)と似ていますが、パターンマッチはより柔軟かつ強力です。パターンマッチは、文章で説明し難く、文章だけで覚えるのは困難です。色々なパターンマッチを書いて覚えるのが得策でしょう。
 パターンマッチは習得しにくいので、ヒントとして私の感覚を書きます。私はパターンマッチを、対象値のパターンから値を決定する機能だとイメージしています。このイメージでパターンマッチを沢山書けばきっとマスターできると思います。
スポンサーサイト



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

F#文法リファレンス - エントリーポイント

概要
 プログラムの開始地点(一番最初に実行する関数)を指定します。

使用に適した状況
 複数のF#プログラムファイルがある場合。

サンプル

(*----------------------------------------------

    エントリーポイント

----------------------------------------------*)

[< EntryPoint >] //属性を使用
let main ( args : string[] ) =
  0 //正常終了を表わす終了コード


文法
 特別な属性「EntryPoint」を関数の前に記述します。終了時の異常有無を知らせるために、最後には必ず0(正常)か、1(異常)を返す必要があります。

解説
 本格的にプログラミングをすると、複数のプログラムファイルにわたり、様々なプログラムを書くことになります。その時、コンパライに対して、どのプログラム(F#では関数)から始めるか伝える必要が生じます。その目印となるのがエントリーポイントです。
 エントリーポイントを指定することにより、プログラムの開始処理と、全てのプログラムが終了するときの処理を指定できます。

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

F#文法リファレンス - コメント

概要
 人間用の文もしくは文章が記述できます。

使用に適した状況
 複雑なプログラムがある場合や、担当者などのプログラムとは関係のない情報を記述したい場合に使用します。解説用プログラムで多用され、実務では多用を良しとしない傾向があります。

サンプル

(*----------------------------------------------

    コメント

----------------------------------------------*)

(* 
  複数行コメント
*)
[< EntryPoint >]
let main ( args : string[] ) = 0 //単一行コメント


文法
 単一行は「//」記号の後に文を書きます。複数行にわたり書きたい場合は、「(*」記号と「*)」」記号で文章を囲みます。

解説
 基本的にプログラムは機械が読むためのものであり、人間に対する説明や補足説明が必要となってくる状況が多々あります。その時のために文法「コメント」が存在します。コメントキーワードが書かれていると、コンパイラは無視して機械向けにプログラムを翻訳します。
 サンプルでは、慣れない人に対して丁寧に解説するために、慣れた人ならば自明の事でも書きます。しかしながら実務では、文法の意味などのプロが知っていて当然のものは書きません。逆に、コメントを書かなくても済む、簡潔で分かりやすいプログラムが求められます。当ブログでの解説用プログラムもしくは、専門書やWeb記事にあるプログラムと、実務で使用するプログラムのコメントの使用法の差異に注意してください。

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

F#文法リファレンス - パイプライン演算

概要
 値の評価順を変更して、プログラムを簡潔にします。

使用に適した状況
 プログラムを簡潔化したい場合。一見地味な効果ですが、プログラムの量が増えるとその効果が実感できると思います。

サンプル

(*----------------------------------------------

    パイプライン演算

----------------------------------------------*)

//1~10のリストを表示
let data = [ 1..10 ]
List.iter ( printf "%d " ) data 

//同じ処理を順次パイプライン演算で実行
[ 1..10 ] |> List.iter( printf "%d " )

//同じ処理を逆順パイプライン演算で実行
List.iter ( printf "%d " ) <| [ 1..10 ]


文法
 順次パイプライン演算子は「|>」、逆順パイプライン演算子は「<|」です。この2つの演算子を使用します。感覚的には「+」などの演算子と変わりません。なお、パイプライン演算は細かく分けると2つあります。順次パイプライン演算子を使用すると順次パイプライン演算、逆順パイプライン演算子を使用すると逆順パイプライン演算と呼びます。

解説
 大量のプログラムを書くと、中間結果をlet束縛するプログラムが増えてきます。少数ならば問題になりませんが、大量になってくると、1つの処理(プログラムの塊)ごとに1行ずつ余分なプログラムが増えることにより、結果として大量にプログラムが増加し、可読性が著しく低下します。この問題による可読性の低下は、注目するべきでないプログラムを省略することにより解決できます。
 パイプライン演算を使用すると、式の評価順を変えることにより、中間結果を束縛するプログラムを減らせます。ただし、あくまでも注目するべきでないプログラムに対して使用するべきだという点を忘れないでください。パイプライン演算を無暗に使用すると、開発ソフトで中間結果を参照しにくくなります。人間が容易に推測できないプログラムは、パイプライン演算を使用せずに、こまめにlet束縛しましょう。

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

F#文法リファレンス - if式

概要
 ある条件により実行する処理を変えたいときはif式(if then式ともいう)を使用します。

使用に適した状況
 現在の状況により返す値を決定したい場合や、状況により実行する処理を変えたい場合に使用します。ただし、基本的な使用法は「適切な値を返す」ことです。最後に値を返すように意識して使用しましょう。

サンプル

(*----------------------------------------------

    if式

----------------------------------------------*)

//if式を使用する関数を定義
let selection x = 
  if ( x > 0 ) then "0以上" 
  elif ( x < 0 ) then "0未満" 
  else "0"

//if式を試す
selection 10 |> printfn "数値は%s"
selection -10 |> printfn "数値は%s"
selection 0 |> printfn "数値は%s"


文法
 「if」キーワード、真偽を返す条件式、「then」キーワード、返す値もしくは条件が真のとき実行する処理を書きます。条件が偽のとき返す値、もしくは実行する処理、「else」キーワードと一連のコードを書きます。なお、複数の条件が考えられるときは、「elif」キーワード、「then」キーワード、返す値もしくは実行する処理を任意の数だけ書きます。

解説
 If式を使用すると、条件を判定して、真偽の結果に従って値を返すことができます。また、コンソール画面にメッセージを出力するなどの特定の処理をすることもできます。ただし、If式本来の使い方は、条件を判定して「適切な値を返す」ことです。一応、printfnのような値を返さない処理を記述することはできますが、それはあくまでも例外的な使用法であり、極力値を返すように意識するべきです。関数プログラミングの基本は、関数屋敷を使って値をやり取りすることであり、副作用を伴う(値を返さない)プログラムは例外です。
 他言語の経験者が引っかかりやすいのは、F#の場合if文ではなくif式だという部分です。式と文の違いは、値を返すところです。If式は必ず値を返さなければなりません。もし体を返さない場合は、返す値がないことを表わす特別な値「unit」を返します。なお、printfnなどの値を返さない命令文は、unitを返すようになっています。

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

F#文法リファレンス - ローカル関数

概要
 関数の内部でのみ使用する関数を定義します。

使用に適した状況
 関数内(関数の本体)のプログラムを簡潔にしたいとき。

サンプル

(*----------------------------------------------

    ローカル関数

----------------------------------------------*)

let Add ( x : int ) ( y : int ) =
  let Inc x = x + 1 //ローカル関数
  let rec Sub x y count = //ローカル再帰関数
    if ( y = count ) then x 
    else Sub <| Inc x <| y <| count + 1
  Sub x y 0
let x = 10
let y = 2
let result = Add x y
printfn "%d + %d = %d" x y result


文法
 関数の本体でインデントを下げ、関数をlet束縛します。ローカル関数は束縛後、適切なスコープ内で自由に使用できます。

解説
 その関数内のでみ使用する関数を定義します。無名関数/匿名関数も同様の効果がありますが、意味合いが異なります。無名関数/匿名関数の方は、名前を付ける必要のない、ただの関数値である事を表わしています。一方、ローカル関数は、現在は特定の関数内でのみ使用するものの、意味があるプログラムの集まりを表わしています。従って、ローカル関数は後で普通の関数に昇格?されることがあります。
 ローカル関数を定義するという事は、読み手に意味があるプログラムの塊があることを示すので、いい加減に定義せず、極力意味が明快になるように意識してプログラミングしましょう。

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

F#文法リファレンス - ラムダ式(無名関数 / 匿名関数)

概要
 ラムダ式と呼ばれる名前がない関数を定義することができます。

使用に適した状況
 局所的にしか使用しない関数を定義したいときや、関数値を定義したいときに使用します。

サンプル

(*----------------------------------------------

    ラムダ式( 無名関数 / 匿名関数 )

----------------------------------------------*)
let add = fun x y -> x + y
let x = 1
let y = 2
printfn "%d + %d = %d" x y <| add x y


文法
 funキーワード、パラメータ、->演算子、本体の順番に記述します。

解説
 プログラミングでは、ループ内でしか使用しないカウンタ用のローカル変数などのように、局所的にしか使用したくないものがあります。同じ発想で、関数型言語であるF#は、局所的に使用する関数を定義することができます
 プログラミングに慣れていない人は、名前がないという事と、局所的という事柄を関連付けて考えにくいと思います。その意味を知るには、名前とは何かを考えなくてはなりません。
 名前というものは何を意味するのでしょうか?名前が意味するところは広く、哲学的に色々な物事が考えられると思いますが、プログラミングでは主に実用面を考えます。実用面から名前を考えると、何かの要素を特定するものだといえます。例えば、アクセス修飾子の問題を考えなければ、加算関数Addは名前を知っていれば他の場所から呼び出せます。ということは、名前がなければ呼び出せないという事でもあります。つまり、プログラミングにおいて、名前がない要素は、他の場所から使用させないという事を表わしています。
 関数型プログラミングに慣れてい居ない人は、他の場所から呼び出す必要がない関数というものをイメージし難いと思います。ですが実は難しいものではなく、簡単かつありふれたものです。
 プログラミングをしていると、関数が複雑になり、プログラムを短く簡潔にするためにヘルパー関数を定義することがあります。そうしてできたヘルパー関数をよく考えると、特定の関数だけしか必要とされていないことが多いです。このヘルパー関数をそのままにしておくと、結果として名前付きで定義された関数の数が増えるので、保守作業にあたっているプログラマーの負担になるかもしれません。もしその時、無名関数であったならば、保守作業をしているプログラマーは、ひとまず注目する必要がない関数だと分かり、読むコードの量を減らせます。
 ほかの用途ももちろんあります。それは高階関数です。高階関数で関数値を返す時、呼び出した側が関数値を名前で束縛するので、名前を付ける必要がありません。そこで返す関数を無名関数にするケースが多いです。
 無名関数は地味な文法ですが、他の文法と組み合わせることにより、プログラム全体の表現力を上げます。また、無名関数を適切に使用すると保守性が向上します。

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

F#文法リファレンス - 関数値を受け取る高階関数

概要
 F#は関数を引数として受け取り処理をする高階関数を定義することができます。関数を引数として指定できると、似たような関数の増加を防げますし、より柔軟なプログラミングが可能となります。

使用に適した状況
 主に、共通したパターンを持つ類似関数が多いときや、動的に作用する関数を定義したいときなどに使用します。関数を受け取る関数は非常に強力で、その可能性は無限大です。

サンプル

(*----------------------------------------------

    高階関数 : 関数を引数として受け取る関数

----------------------------------------------*)

//指定した関数に値を適用して結果を返す高階関数
//※「 'a 」は型を問わない
let Apply ( f : 'a -> 'a -> 'a ) x y = f x y
 
 //高階関数を試用する
let x = 10
let y = 2
let f = fun x y -> x * y 
printfn "%d * %d = %d" x y <| Apply  f x y


文法
 引数として関数を受け取る高階関数専用の文法はありません。引数の型として関数を指定するだけです。

解説
 関数をよく観察すると、同様のパターンで動作する関数は多いです。それらの似た関数を扱う機能があれば、より柔軟かつ強力なプログラミングが可能となります。その望みをかなえるのが高階関数です。
 関数値の引数を受け取る関数は、関数そのものを扱えるので、命令型プログラミングでは考えられなかった処理が可能となります。例えば、実行時に適用する関数を変化させることができますし、類似関数をプログラミングする労力から解放されます。類似関数の定義がなくなるという事は、保守性に優れたプログラムが欠けるようになります。ただし、あまりにも抽象化しすぎると、意味が分からない関数が出来上がり、保守性を著しく下げるので、十分に注意してください。何事もやりすぎは毒なのです。

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

F#文法リファレンス - 関数を返す高階関数

概要
 関数を値として扱う関数を高階関数と呼びます。値としての函数である関数値は、引数として指定することもできますし、呼び出し元へ返すこともできます。この記事は関数を返す高階関数についての記述です。

使用に適した状況
 関数に共通したパターンがあり、抽象化できるときに使用するとよいでしょう。関数を抽象化すると、似た定義の関数の増加を防ぎ、より柔軟なプログラミングが可能となります。

サンプル

(*----------------------------------------------

    高階関数 : 関数を返す関数

----------------------------------------------*)

//演算関数を返す高階関数
let operation ( x : char ) : ( int -> int -> int) = 
  match x with
    | '+' -> ( fun y z -> y + z )
    | '-' -> ( fun y z -> y - z )
    | '*' -> ( fun y z -> y * z )
    | '/' -> ( fun y z -> y / z )
    | _ -> raise <| 
            new System.ArgumentException( x.ToString() + "は対応していません。" )

//高階関数を試すためのヘルパー関数
let applyOpe ope =
  let x = 10
  let y = 2
  let pf = operation( ope )
  let r =  pf x y
  printfn "%d %c %d = %d" x ope y r

//各種演算を試す
applyOpe '+' |> ignore
applyOpe '-' |> ignore
applyOpe '*' |> ignore
applyOpe '/' |> ignore


文法
 関数値を返す高階関数は特別な文法を持ちません。関数値を戻り値とする関数を定義すると、関数を返す高階関数を定義できます。

解説
 プログラミングの基本は、物事を抽象化して考える事です。関数も例外ではありません。従来の命令型プログラミングに慣れている人は、一般にデータだけを抽象化して考える傾向がありますが、関数も抽象化して考えられます。具体的に言うと、サンプルで示した演算子ように、一部のプログラムだけ違う関数は沢山あります。それらの関数を抽象化して考える事により、プログラミング可能な領域と発想が広がります
 関数値を返す高階関数は実に強力です。始めは違和感を覚えるかもしれませんが、慣れれば関数を抽象化して考えるのが当たり前になります。その状態になったとき、貴方のプログラミング力が一段階上がっていると言えると思います。

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

F#リファレンス - 関数

概要
 関数を定義します。

使用に適した状況
 F#は関数型言語なのでいつでも適しています。おそらく、関数を一切使用しない関数型プログラミングは考えられないでしょう。

サンプル

(*----------------------------------------------

    関数

----------------------------------------------*)

//定義
let pow x = x * x

//呼び出し
let result = pow 10
printfn "値%d" result

(*
浮動小数点も可能
引数の型は推論される
let result = pow 1.0
printfn "値%f" result
*)

//パラメータの型を明示して関数を定義
let multiply ( x : int ) ( y : int ) = x * y
let value = multiply 10 2
printfn "値%d" value


文法
 変数名、パラメーター、=記号、関数の本体の順番に書きます。基本的に型は明示する必要がありません。F#が型を推論してくれます。もちろん、使用目的がはっきりしている場合は、型を明示したほうが良いでしょうが、型に依存しない関数は多いでしょう。
 型を明示する場合は、丸括弧内にパラメータ名 、「:」記号 、型名の順に記述します。パラメータが1つの場合は丸括弧は必要ありません。

解説
 F#は関数型言語なので、他言語に比べると自由に関数を定義できます。例えば、任意の場所で関数を束縛できますし、入れ子構造の関数など(他の記事で説明)も簡単に定義できます。
 F#のプログラミングでは基本的に、関数のパラメータをF#に型推論させます。何故ならば、物事を抽象化し関数としてみた場合、型に依存したものでないことが多いからです。サンプルを例に挙げて言うと、2乗および掛け算は整数に限ったものではありません。浮動小数でも使用できますし、演算を定義していれば、どのような型でも適用可能です。

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

プロフィール

インドリ

Author:インドリ
みなさん、はじめまして、
コンニチハ。

ボクは、無限の夢(infinity dream)を持つネタ好きな虹色の鳥インドリ(in dre)です。
色々な情報処理技術を啄ばむから楽しみにしてね。

http://twitter.com/indori
は別人による嫌がらせ行為です。
私とは関係ないので注意して下さい。
次はなりすましブログなどをするかもしれませんが、ここ以外でブログをするつもりがないので、ここ以外にインドリのブログがあったとしても無視してください。


何度言っても分からない人がいるので、ここにコメント欄へ書き込むときの注意事項を書きます。


一、社会人としてのマナーをわきまえましょう。
一、妄想に基づく書き込みを止めてください。
一、暴言の類は書かないで下さい。
一、某誹謗中傷サイトの書き込みは彼らの妄想に基づく書き込みですから無視して、ここへ書き込まないで下さい。
一、コメント書く前に他のコメントよく読んでから行って下さい。
一、言いがかかり等の行為を禁止します。
一、その他常識的に考えて迷惑なコメントはしないで下さい。


以上のルールを守れない人のコメントは削除します。



利用上の注意
ここに紹介してある文章およびプログラムコードは正確であるように心がけておりますが、内容を保証するものではありません。当サイトの内容によって生じた損害については、一切の責任を負いませんので御了承ください。


執筆したCodeZineの記事


【VB.NETで仮想CPUを作ろう】

  1. VB.NETで仮想CPUを作ろう
  2. レジスタの実装
  3. 仮想CPUのGUI化
  4. テストドライバの改良
  5. CPUの基礎動作の実装
  6. MOV命令の実装
  7. ADD命令実装
  8. SUB命令実装
  9. INC命令&DEC命令の実装と命令長
  10. MLU命令の実装とModR/Mについて
  11. DIV命令の実装とイベント設計について
  12. 機械語駆動式 関数電卓を作ろう!
  13. 機械語駆動式 関数電卓を作ろう! 解答編(前半)
  14. 機械語駆動式 関数電卓を作ろう! 解答編(後半)


【仮想ネットワーク実装でTCP/IPを学ぼう】
  1. TCP/IPの基礎と勘所
  2. ネットワークアクセス層の勘所
  3. インターネット層の勘所
  4. トランスポート層の勘所
  5. アプリケーション層の勘所
  6. セキュリティの基礎と仮想ネットワークの仕様
  7. GDI+と独自プロトコルの定義



【並列化】
インテル Parallel Studioを使って並列化プログラミングを試してみた
並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」


【TBBシリーズ】
  1. インテル スレッディング・ビルディング・ブロックの概要
  2. インテルTBBから学ぶループの並列化
  3. スレッドセーフとインテルTBBのコンテナ
  4. インテルTBBのスレッドクラス


【OpenMPシリーズ】
  1. OpenMPの基礎構文
  2. OpenMPの実行時ライブラリと並列ループ
  3. OpenMPのメモリモデルとfork- joinモデル

最近の記事
最近のコメント
月別アーカイブ
カテゴリ
Ada (9)
COBOL (5)
C (9)
C++ (11)
C# (370)
D (25)
Java (8)
Perl (1)
Ruby (14)
PHP (2)
Boo (2)
Cobra (2)
LISP (6)
F# (33)
HTML (0)
XHTML (0)
CSS (0)
XML (0)
XSLT (0)
Scala (4)
WPF (0)
WF (2)
WCF (0)
LINQ (4)
MONO (5)
Linux (0)
MySQL (0)
ブログ内検索
リンク
最近のトラックバック
RSSフィード
ブロとも申請フォーム

この人とブロともになる

QRコード
FC2カウンター