M.Hiroi が F# の勉強で書いたジャンクスクリプトです。
F# は Microsoft が開発した関数型言語とオブジェクト指向を融合したマルチパラダイムなプログラミング言語です。ベースとなった関数型言語は OCaml です。C# と同じく、共通言語ランタイム (CLR) が解釈する共通中間言語 (CLI) にコンパイルされて実行されます。
F# (や C#) のプログラムを実行するには CLR が必要になりますが、MicroSoft 社が開発していた .NET Framework、オープンソースプロジェクトの .NET Core や Xamarin / Mono は .NET に統合されることになりました。現時点 (2022 年 3 月) の最新版は 2021 年 11 月にリリースされた .NET 6 になります。.NET 6 は LTS (long term support) なので、今後は .NET 6 へ移行するユーザーも増えていくのではないでしょうか。
F# でプログラムを作る場合、.NET SDK をインストールすれば最低限の開発環境が整います。統合開発環境 (Visual Studio など) もありますが、本ページではそれを使わずに、エディタで簡単なプログラムを作りながら、F# の基本を勉強していくことにします。なにぶんにも初心者が作るページなので、勘違いや間違いがあると思います。何かお気づきの点がありましたら、メールでご指摘いただけると助かります。本ページは F# に関する M.Hiroi の「覚え書」にすぎませんが、よろしければお付き合いくださいませ。
.NET の場合、.NET SDK をインストールすれば最低限の開発環境が整うので、C# や F# の学習が目的ならば .NET SDK のほうが簡単かもしれません。.NET SDK は .NET の Download .NET からダウンロードすることができます。インストールの方法は以下のページに詳しく書かれています。
M.Hiroi は 3. に書かれている スクリプトでのインストール で .NET SDK を Ubuntu 18.04 (WSL) にインストールしました。これはインストール用のシェルスクリプト dotnet-install.sh をダウンロードして、シェル (bash) で実行するだけです。.NET SDK は ~/.dotnet に展開されるので、そこにパスを通すことと、環境変数 DOTNET_ROOT の設定をお忘れなく。以下のコマンドを .bashrc などに記述しておくと良いでしょう。
export PATH=$HOME/.dotnet:$PATH export DOTNET_ROOT=$HOME/.dotnet
.NET SDK でプログラムを作る場合、dotnet というコマンドラインツール (CLI) を使います。たとえば、コンソールアプリケーションを作成する場合、プログラムを作成するディレクトリ (プロジェクト) で次のコマンドを実行します。
dotnet new console -lang F# [-o name]
dotnet new はプロジェクトを初期化するコマンドです。作成するプログラムの種類 (C# / F# / VB) はオプション -lang で指定することができます。省略した場合は C# になります。これでカレントディレクトリにプログラム (Program.fs) と、プロジェクトに必要なデータが生成されます。ソースファイルの拡張子には fs が使用されます。
また、オプション -o (--output) で作成するプロジェクトを指定することもできます。たとえば、-o hello とするとカレントディレクトリにサブディレクトリ hello が作られて、そこにプロジェクトが生成されます。
プログラムは次のコマンドで実行することができます。
dotnet run [--project name]
オプション --project で実行するプロジェクトを指定します。省略した場合、カレントディレクトリのプロジェクトが実行されます。
簡単な実行例を示しましょう。
$ dotnet new console -lang F# -o hello テンプレート "コンソール アプリ" が正常に作成されました。 作成後の操作を処理しています... /home/mhiroi/fsharp/hello/hello.fsproj で ' dotnet restore ' を実行しています... 復元対象のプロジェクトを決定しています... /home/mhiroi/fsharp/hello/hello.fsproj を復元しました (4.84 sec)。 正常に復元されました。 $ ls hello Program.fs hello.fsproj obj $ cat hello/Program.fs // For more information see https://aka.ms/fsharp-console-apps printfn "Hello from F#" $ dotnet run --project hello Hello from F#
実行形式ファイルは次のコマンドで生成します。
dotnet publish [-c conf] [project]
project を省略するとカレントディレクトリのプロジェクトが対象となります。オプション -c (--configuration) を省略した場合、デフォルト値の Debug が使用され、デバッグ用の実行形式ファイルが生成されます。Release を指定すると、リリース用の実行形式ファイルが生成されます。
オプション -c は dotnet run でも使用することができます。なお、実行形式ファイルを出力するディレクトリはオプション -o (--output) で指定することができます。
簡単な実行例を示しましょう。
$ dotnet publish hello .NET 向け Microsoft (R) Build Engine バージョン 17.0.0+c9eb9dd64 Copyright (C) Microsoft Corporation.All rights reserved. 復元対象のプロジェクトを決定しています... 復元対象のすべてのプロジェクトは最新です。 hello -> /home/mhiroi/fsharp/hello/bin/Debug/net6.0/hello.dll hello -> /home/mhiroi/fsharp/hello/bin/Debug/net6.0/publish/ $ cd hello/bin/Debug/net6.0/publish $ ls FSharp.Core.dll de fr hello.deps.json hello.pdb it ko pt-BR tr zh-Hant cs es hello hello.dll hello.runtimeconfig.json ja pl ru zh-Hans $ ./hello Hello from F# $ dotnet hello.dll Hello from F#
$ dotnet publish -c Release hello .NET 向け Microsoft (R) Build Engine バージョン 17.0.0+c9eb9dd64 Copyright (C) Microsoft Corporation.All rights reserved. 復元対象のプロジェクトを決定しています... 復元対象のすべてのプロジェクトは最新です。 hello -> /home/mhiroi/fsharp/hello/bin/Release/net6.0/hello.dll hello -> /home/mhiroi/fsharp/hello/bin/Release/net6.0/publish/ $ cd hello/bin/Release/net6.0/publish $ ls FSharp.Core.dll de fr hello.deps.json hello.pdb it ko pt-BR tr zh-Hant cs es hello hello.dll hello.runtimeconfig.json ja pl ru zh-Hans $ ./hello Hello from F# $ dotnet hello.dll Hello from F#
実行形式ファイルの名前は、デフォルトでプロジェクト名と同じになります。プログラムの実行は ./hello のように実行形式ファイルを直接実行するだけではなく、dotnet hello.dll のように dotnet に dll ファイルを渡すことでもできます。
F# を学習する場合、Lisp / Scheme などの関数型言語や Python のような対話モード (REPL) があると便利です。F# の場合、dotnet fsi で対話モード (REPL) を起動することができます。
$ dotnet fsi Microsoft (R) F# インタラクティブ バージョン F# 6.0 のための 12.0.0.0 Copyright (C) Microsoft Corporation. All rights reserved. ヘルプを表示するには次を入力してください: #help;; > 1 + 2;; val it: int = 3 >
REPL を終了するには #quit;; または CTRL-D を入力してください。
また、dotnet fsi はスクリプト言語のようにプログラム (ソースファイル) を実行することもできます。この場合、ソースファイルの拡張子には .fsx を使うのが習慣のようです。
$ cat hello.fsx printfn "Hello World!!" $ dotnet fsi hello.fsx Hello World!!
本稿では、主に dotnet fsi を使って F# の学習を進めていくことにします。
さて、肝心な F# の実行速度ですが、いつものように「たらいまわし関数」を使って調べてみました。
リスト : たらいまわし関数 (Tak.fsx) let rec tak x y z = if x <= y then z else tak (tak (x - 1) y z) (tak (y - 1) z x) (tak (z - 1) x y)
関数 tak は OCaml 入門: はじめに で作成したプログラムと同じです。REPL からプログラムを読み込むにはコマンド #load を使います。実行時間は #time で計測することができます。実行結果は次のようになりました。
> #load "Tak.fsx";; [読み込み中 /home/mhiroi/fsharp/Tak.fsx] namespace FSI_0002 val tak: x: int -> y: int -> z: int -> int > open Tak;; > #time;; --> 今すぐタイミング オン > tak 22 11 0;; リアル: 00:00:01.693、CPU: 00:00:01.750、GC 全般0: 0, 全般1: 0, 全般2: 0 val it: int = 11 >
処理系 | 秒 |
---|---|
SBCL (ver 1.4.5) | 6.38 |
LuaJIT (var 2.1.0-β) | 4.02 |
SML/NJ (ver 110.98) | 2.66 |
GHC (ver 8.8.4) | 1.96 |
Julia (ver 1.6.4) | 1.95 |
F# (ver 6.0) | 1.69 |
SBCL (最適化) | 1.57 |
GCC -O2 (ver 7.4.0) | 1.23 |
Go 言語(ver 1.17.4) | 1.21 |
Scala (ver 2.13.5) | 1.07 |
ocamlopt (ver 4.05.0) | 0.97 |
Java (ver 11.0.10) | 0.95 |
F# はネイティブコードにコンパイルするプログラミング言語に匹敵する結果になりました。この結果には M.Hiroi も驚きました。.NET と F# は優秀な処理系だと思います。興味のある方はいろいろ試してみてください。
『お気楽 F# プログラミング超入門』の著作権は筆者「広井誠 (Makoto Hiroi)」が保持します。無断使用や無断転載は禁止いたします。『お気楽 F# プログラミング超入門』で作成したプログラムはフリーソフトウェアとします。ご自由にお使いください。プログラムの改造や配布もご自由にどうぞ。その際は出典を明記してくださるようお願いいたします。
ただし、ドキュメントの内容とプログラムは無保証であり、利用したことにより生じた損害について、作者「広井誠 (Makoto Hiroi)」 は一切の責任を負いません。また、これらのプログラムを販売することで利益を得るといった商行為は禁止いたします。