open netshop

Chapter 1. はじめに

Table of Contents

1. F#について
2. インストールと起動
2.1. インストール
2.2. F#インタプリタの起動
3. F#チュートリアル

1. F#について

F#は.NET Framework上で動作する新たな言語で、Visual Studio 2010から標準搭載されます。F#は基本的には関数型言語と呼ばれる種類の言語ですが、オブジェクト指向プログラミングや命令型(手続き型)プログラミングもサポートしているため、関数型言語がベースのマルチパラダイム言語といったほうが適切です。また、さまざまな近代的な関数型プログラミングの機能を備えており、関数型プログラマから注目を集めているモナド構文もサポートしています。

F#はObjective Caml(OCaml)というフランスの国立研究機関が開発した言語を元に作られました。したがって、基本的な文法はOCamlと同じで、一部の機能を除けばそのままコンパイル可能です。しかしF#では、OCamlの文法を簡略化した軽量構文(lightweight syntax)という文法が推奨され、こちらが基本的な文法となります。

F#には、他のVisual StudioファミリーのC#やVB.NETにはない大きな特徴があります。それはインタプリタの存在です。インタプリタとは、コマンドプロンプトなどのようにコンソール上から直接プログラムコードを入力して実行できる環境です。C#やVB.NETは基本的にソースコードをコンパイルして、生成された実行可能ファイルを実行するという手順を踏みます。F#も当然コンパイルして実行可能ファイルを生成することができますが、同時にインタプリタも提供しています。インタプリタを使うと、プログラムコードを入力するたびに応答が得られるので、さまざまなコードを試したりするのに非常に向いています。たとえば、ウィンドウを生成して実際に画面上にウィンドウを出したまま、そのウィンドウのプロパティをいろいろ変化させるといったことが可能です。

2. インストールと起動

ここではF#の環境のインストールと起動方法について説明します。

このサイトでは、基本的にF#インタプリタを用いて解説をしていきます。F#インタプリタには、コンソール版とVisual Studio版の2種類があります。コンソール版はコマンドプロンプト上で動作する対話モードで、Visual Studio版はVisual Studio内の子ウィンドウとして動作します。

基本的にはどちらを使ってもいいのですが、ここではVisual Studio版を使うことをお勧めします。Visual Studio版を使うと、Visual Studio上のソースコードエディタ上でF#のコードを選択してAlt+Enterを押すことで、その選択範囲内のコードをF#インタプリタに送ることができ、タイプミスした場合のやり直しが容易にできます。また、現在のバージョン(Visual Studio 2010 beta 1; v1.9.6.16)のコンソール版では、F#インタプリタ自体が2バイト文字をきちんと処理していないため、ひらがなや漢字の入力ができないという問題があります。

Note

実はこの問題は、F#インタプリタ自体にパッチを当てることで解決します。この件に関しては改めて説明する予定ですが、現在いげ太さんのブログで詳しく説明してくださっているので、そちらをご覧ください。

2.1. インストール

現在F#の環境をインストールするには、以下のような選択肢があります。

  • Visual Studio 2010 beta 1(ProfessionalTeam Systemなど) (421MB~1231MB)

    将来製品として発売されるVisual Studioのベータ版。Visual Studioの機能がフルで使えますが、インストールに必要なディスク容量が多く、インストールにも時間がかかります。

  • Visual Studio 2008 Shell (Integrated) SP1+ F#コンパイラ (530MB)

    Visual Studio 2008 Shellは、製品版のVisual Studio 2008からC++/C#/VB.NET/F#などのコンパイラを抜いた無料の統合開発環境です。初期状態ではコンパイラが何も含まれていないが、F#などの自分の好きなコンパイラを入れることができます。もしVisual Studio 2008 Professional以上をお持ちの場合は、そちらにも組み込まれるので、Visual Studio 2008 Shellを別途インストールする必要はありません。

    この組み合わせは必要最低限のGUIとコンパイラのみがインストールされるので、比較的要求されるディスク容量はあまり要求されず、インストール時間もあまり長くありません。

    ちなみに、Visual Studio 2008 ShellにはIsolated Modeというものも存在しますが、こちらではF#は使えないので注意が必要です。さらに、Visual Studio 2010版のVisual Studio Shellも提供されていますが、こちらでもまだF#を使うことはできません。

  • F#コンパイラ(21MB)

    最低限のF#のコンパイラとF#インタプリタとF#ライブラリのみをインストールします。統合開発環境が提供されないかわりに、インストールはすぐに完了します。このコンパイラのみインストールした場合は、基本的にコマンドプロンプト上から操作することになります。

以下ではそれぞれのインストール方法について説明するので、お好きなものを選んでください。

2.1.1. Visual Studio 2010 beta 1のインストール

Visual Studio 2010 beta 1から適当なものをインストールします。どれを選べばわからない場合は、Team System Web Installerなどをインストールしておけば問題ありません。インストール作業自体は、簡単なウィザードに従うだけで完了します。途中で再起動を要求される場合があります。

2.1.2. Visual Studio 2008 Shell (Integrated) SP 1 + F#コンパイラ

まずはVisual Studio 2008 Shellを先にインストールします。こちらを先にインストールしておかないと、F#の環境がうまくVisual Studio 2008 Shellに組み込まれない場合があるので注意が必要です。インストールの手順は以下のとおりです。

  1. 入手したvs_ideredist.exeを起動するとウィザードが立ち上がるので、どんどん次へ進んでウィザードを完了します。ここで注意なのですが、このvs_ideredist.exeは単なる自己展開プログラムで、指定したディレクトリにVisual Studio 2008 Shellのセットアッププログラムを展開するだけです。

  2. 展開先にvside.enu.exeというセットアッププログラムがあるので、実行してどんどん次へ進んでウィザードを完了します。これでVisual Studio 2008 Shellがインストールされます。

次にF#コンパイラをダウンロードしてインストールします。コンパイラ自体のインストールはすぐに完了して、スタートメニューに登録されます。

2.1.3. F#コンパイラ

F#コンパイラをダウンロードしてインストールします。コンパイラ自体のインストールはすぐに完了して、スタートメニューに登録されます。

2.2. F#インタプリタの起動

スタートメニューからVisual Studio 2010 beta1 またはVisual Studio 2008 Shellを起動します。Visual Studio 2010 beta 1をインストールした場合は、初回起動時にVisual Studioをどの言語に特化した環境に設定するかを聞かれますが、このときにVisual F#を選択しておくと、起動した直後に標準でF#インタプリタのウィンドウが開きます。もし他の言語用の設定などにして、起動直後にF#インタプリタのウィンドウが開いていない場合でも、メインメニューから「View - Other Windows - F# Interactive」を選択すると、Visual Studio上にF# Interactiveという子ウィンドウが表示され、その中でF#インタプリタが起動します。もしVisual Studioを入れずにF#コンパイラのみの入れた方は、スタートメニューから「Microsoft F# CTP 1.9.6.16 - F# Interactive (Console)」を選択すると、コマンドプロンプト上でF#インタプリタが起動します。

このインタプリタに対してF#のコードを入力していきます。ちなみに、Visual Studioをインストールした場合は、何でもいいので適当なF#のプロジェクトを作成しておくと、F#のソースコードエディタが利用できるので便利です。さらにソースコードエディタを使う場合、エディタ上からF#のコードを範囲選択してAlt+Enterキーを押すと、その選択した部分がF#インタプリタに入力として転送されるので、少し行数が多い場合はこちらを使うとよいでしょう。

F#インタプリタでは、軽量構文が標準で有効になっています。軽量構文では、Pythonのように半角スペースによるインデントによってコードブロックを表現します。ちょっとここでコードブロックについて簡単に説明しておきます。もし、ここではよく理解できなくても後で詳しく説明するので、ここで無理に理解する必要はありません。

Note

F#のコードブロックとは、C#いうとメソッド定義やif文などであらわれる{}で囲まれたコード片に相当する概念です。例えば以下のコードでは、{}で囲まれたmessageの宣言とWriteLineメソッド呼び出しの部分をブロックといいます。

for(int i = 0; i < 10; i++)
{
    string message = "Hello, world!";
    Console.WriteLine(message);
}

コードブロックの基本的な考え方は、インデントレベルが現在のレベルより下に下がったところがブロックの開始となり、インデントレベルが元に戻った(または元の位置より上のレベルに上がった)ところがブロックの終了になります。

例えば以下の図を見てください(ここでは便宜的に行番号を書いていますが、実際のF#のコードでは行番号を書くことは許されません)。最初に、ソースファイル全体にわたるトップレベルというスコープが存在します。このトップレベルから始まる宣言は、ソースファイル全体で参照することができます。

次に、2行3列目においてインデントが1レベル下がり、ここからひとつのブロック(仮にブロック1と命名)が始まります。このブロック1は、7行目でインデントレベルが元に戻っている直前まで続きます。また、このブロック1は、5行5列目においてさらにレベルが下がり、ここからまた新たなブロック(仮にブロック2と命名)が始まります。このブロックも、7行目でインデントレベルが元の位置より上のレベル(この場合はトップレベル)に戻るため、6行目がブロック2の終了となります。そして、8行目からはまた新たにインデントが下がり、ブロック3が始まり、ソースファイルの最終行まで続きます。

3. F#チュートリアル

ここでF#インタプリタを使って、F#に少し簡単に触れてみましょう。まずは定番のHello, world!からです。

F# Version 1.9.6.2, compiling for .NET Framework Version v2.0.50727

Please send bug reports to fsbugs@microsoft.com
For help type #help;;

> printf "Hello, world!\n";;
Hello, world!
val it : unit = ()

> printfn "Hello, world!";; // 行末で改行
Hello, world!
val it : unit = ()

> open System.Windows.Forms;; // 名前空間を開く
> MessageBox.Show("Hello, world!");; // Windows Formsのメッセージボックスを呼び出す
val it : DialogResult = OK

> System.Windows.Forms.MessageBox.Show("Hello, world!");; // 完全修飾名で呼び出す
val it : DialogResult = OK

> System.IO.Directory.GetCurrentDirectory();;
val it : string = "c:\\Program Files\\Microsoft Visual Studio 9.0\\Common7\\IDE"

F#インタプリタでは、入力の完了として入力の最後に;;というセミコロンを2つ続けたものを入力します。したがって、単なる改行記号は入力の完了ではないので注意してください。

本サイトでは、ユーザがF#インタプリタ上に対して入力する文字列を「入力」と呼び、色つきのフォントで表します。また、ユーザの入力に対して、F#インタプリタが返す文字列を「応答」と呼びます。上の例では、val itから始まる行が F#からの応答となります(Hello, world!の文字列はF#インタプリタ自体が返した応答ではなく、自分が入力したプログラムが出力した文字列なので注意してください)。

コンソールに文字を出力するには、printf関数を使います。printfn関数を使うと行末で自動的に改行してくれます。メッセージボックスを表示するには、まずWindows Formsの名前空間を開き、MessageBoxクラスのShow静的メソッドを呼び出します。また、次の入力のように完全修飾名で呼び出すこともできます。同様にして、C#でもお馴染みの他の.NETのクラスも利用することができます。

上の入力例においてval itではじまる行は、その直前の入力を実行した結果の値を意味します。F#インタプリタでは、実行結果の値は自動的にitという変数に割り当てられます。printfおよびprintfnの戻り値はunit型というもので、ちょうどvoidに相当するものです。MessageBox.Showの結果はDialogResult値が返ってきています。

単一行のコメントは//というスラッシュを2つつづけたもののあとに書くことができ、複数行のコメントは(**)で囲われた部分に書くことができます。

次に簡単な計算をやってみましょう。

> 3;;
val it : int = 3
> 3 + 5;;
val it : int = 8
> (3 + 2) * 5 / 10;;
val it : int = 2

変数への代入は、以下のようにletを使います。

> let x = 3;;
val x : int

> let y = 5;;
val y : int

> x + y;;
val it : int = 8

入力の直後にvalに続けて変数名とその型が表示されていることがわかります。 ちなみに後で詳しく説明しますが、このサイトではこれらを変数とは呼ばず識別子という呼び方をします。

関数は以下のように定義し、C#のように引数全体を括弧で囲む必要は基本的にありません。

> let plus x y = x + y;;
val plus : int -> int -> int

> plus 3 2;;
val it : int = 5

ここで少し注目してもらいたいのが、先ほどの変数(識別子)の定義のときも関数の定義と同様にletを使っていることです。ここが関数型言語としての特徴で、値と関数を同じように扱うことができます。実際、関数も関数値という値として扱われ、ふつうの値のように簡単に代入したり、引数として渡したり、戻り値として返したりすることができます。

> let plus2 = plus;; // 関数を別の変数(識別子)に代入
val plus2 : (int -> int -> int)

> plus2 5 3;;
val it : int = 8

ここまでに紹介したのはごく一般的な機能ですが、ここでF#の特徴的な機能をいくつか紹介しておきましょう。

まずは計量単位(units of measure)です。これは物理でいう次元解析に相当するもので、たとえば値にメートルやグラムなどの単位情報を付加し、誤って違う単位同士を足してしまったりする間違いを防ぐことができます。

> [<Measure>] type kg;; // 体重の単位
[<Measure>]
type kg

> [<Measure>] type m;; // 身長の単位
[<Measure>]
type m

> [<Measure>] type BMI = kg / m^2;; // BMI指数の単位
[<Measure>]
type BMI = kg/m ^ 2

> let weight = 50.0<kg>;; // 体重
val weight : float<kg>

> let tall = 1.60<m>;; // 身長
val tall : float<m>

> let bmi = weight / (tall*tall);; // BMI指数を計算
val bmi : float<kg/m ^ 2>

> let standard_BMI = 22.0<BMI>;; // 標準BMI指数
val standard_BMI : float<BMI>

> standard_BMI < bmi;; // 標準BMI指数との比較
val it : bool = false

> standard_BMI < tall;; // 標準BMI指数と身長の比較(単位が違うのでエラー)
  standard_BMI < tall;;
  ---------------^^^^^

stdin(45,16): error FS0001: Type mismatch. Expecting a
  float<BMI>
but given a
  float<m>.
The unit of measure 'BMI' does not match the unit of measure 'm'

次に紹介するのはシーケンス式(sequence expression)です。これを使うと規則的な数列やデータ列を簡単に作り出すことができます。

> [ 1..10 ];;
val it : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]

> [ for x in [ 1..5 ] -> x ];;
val it : int list = [1; 2; 3; 4; 5]

> [ for x in [ 1..5 ] -> x * 2 ];;
val it : int list = [2; 4; 6; 8; 10]

> [ for x in [ 1..5 ] ->
    [ for y in [ 1..x ] -> (x,y) ]
  ];;
val it : (int * int) list list
= [[(1, 1)]; [(2, 1); (2, 2)]; [(3, 1); (3, 2); (3, 3)];
   [(4, 1); (4, 2); (4, 3); (4, 4)]; [(5, 1); (5, 2); (5, 3); (5, 4); (5, 5)]]

実はこのシーケンス式の背景には、モナド(monad)という概念が隠れています。F#にはワークフローというモナド構文が存在し、シーケンス式はそれを用いて実装された機能なのです。F#ではほかにも、マルチスレッドを扱うのに特化した非同期ワークフロー(asynchronous workflow)や、構文解析を行うライブラリのFParsecがワークフローを用いて実装されています。

inserted by FC2 system