次の方法で共有


F# による対話型プログラミング

F# インタラクティブ (dotnet fsi) は、コンソールで F# コードを対話形式で実行したり、F# スクリプトを実行したりするために使用します。 つまり、F# インタラクティブは、F# の REPL (Read、Evaluate、Print Loop) を実行します。

コンソールから F# インタラクティブを実行するには、dotnet fsi を実行します。 dotnet fsi はすべての .NET SDK に備わっています。

メモ

.NET Framework ランタイムで F# インタラクティブを使用する場合は、Visual Studio Build Tools または Visual Studio のエディションがインストールされている必要があり、コマンド ラインの代わりに FsiAnyCPU.exe コマンドを「開発者コマンド プロンプト」から呼び出すか FsiAnyCPU.exe 環境変数で PATH 使用できるようにする dotnet fsi 必要があります。

ツールでは、バージョン F# インタラクティブ ランタイムの定義がサポートされます。

  • Visual Studio: メニュー バーで [ツール] / [オプション][F# ツール] / [F# インタラクティブ] の順に移動し、[.NET Core スクリプトを使用] を調整します。
  • Visual Studio Code (ionide 拡張機能): コマンド パレットで、[ユーザー設定: ユーザー設定を開く][拡張機能] / [F#] / [FSharp: Fsi Sdk ファイル パス] の順に移動します。

使用できるコマンド ライン オプションについては、「F# Interactive オプション」を参照してください。

F# インタラクティブでコードを直接実行する

F# インタラクティブは REPL (read–eval–print loop) であるため、コードを対話形式で実行できます。 コマンド ラインから dotnet fsi を実行した後の対話型セッションの例を次に示します。

Microsoft (R) F# Interactive version 11.0.0.0 for F# 5.0
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> let square x = x *  x;;
val square : x:int -> int

> square 12;;
val it : int = 144

> printfn "Hello, FSI!"
- ;;
Hello, FSI!
val it : unit = ()

次の 2 つの主要な点がわかります。

  1. すべてのコードは、評価するために 2 つのセミコロン (;;) で終了する必要があります
  2. コードは評価され、it 値に格納されます。 it は対話的に参照できます。

F# インタラクティブでは、複数行の入力もサポートされています。 2 つのセミコロン (;;) を使用して、入力を終了する必要があります。 F# インタラクティブに対して貼り付けられ、評価された、次のスニペットを考えてみましょう。

> let getOddSquares xs =
-     xs
-     |> List.filter (fun x -> x % 2 <> 0)
-     |> List.map (fun x -> x * x)
-
- printfn "%A" (getOddSquares [1..10]);;
[1; 9; 25; 49; 81]
val getOddSquares : xs:int list -> int list
val it : unit = ()

>

コードの書式設定は保持されており、入力を終了する 2 つのセミコロン (;;) があります。 その後 F# インタラクティブによってコードが評価され、結果が出力されています。

F# を使用したスクリプト

F# インタラクティブでの対話的なコードの評価は学習ツールとしては優れていますが、通常のエディターでコードを記述するほど生産的ではないことがすぐにわかります。 通常のコード編集をサポートするために、F# スクリプトを記述することができます。

スクリプトで使用されるファイル拡張子は .fsx です。 ソース コードをコンパイルしてからコンパイルしたアセンブリを実行する代わりに、dotnet fsi 実行してスクリプトのファイル名を指定するだけで、F# Interactive はコードを読み取ってリアルタイムで実行できます。 たとえば、Script.fsx という名前の次のスクリプトを考えてみます。

let getOddSquares xs =
    xs
    |> List.filter (fun x -> x % 2 <> 0)
    |> List.map (fun x -> x * x)

printfn "%A" (getOddSquares [1..10])

このファイルをコンピューター上に作成したら、dotnet fsi を使用して実行し、ターミナル ウィンドウで直接出力を確認することができます。

dotnet fsi Script.fsx
[1; 9; 25; 49; 81]

Shebang でのスクリプトの実行

dotnet fsiを明示的に呼び出さずに F# スクリプトを実行可能にするには、スクリプトの上部にある shebang 行を使用できます。 これにより、シェル スクリプトのようにターミナルから直接スクリプトを実行できます。

たとえば、次の内容を含む ExecutableScript.fsx というスクリプト ファイルを作成します。

#!/usr/bin/env -S dotnet fsi

let getOddSquares xs =
    xs
    |> List.filter (fun x -> x % 2 <> 0)
    |> List.map (fun x -> x * x)

printfn "%A" (getOddSquares [1..10])
  1. スクリプトを実行可能にする:chmod コマンドを使用してスクリプトを実行可能にします。

    chmod +x ExecutableScript.fsx
    
  2. スクリプトを直接実行する: 今すぐ、ターミナルから直接スクリプトを実行できます。

    ./ExecutableScript.fsx
    

注意: Shebang 機能 (#!) は、Linux や MacOS などの Unix に似たシステムに固有です。 Windows では、ターミナルまたはコマンド プロンプトで直接 dotnet fsi Script.fsx を使用してスクリプトを実行できます。

この機能を使用すると、Linux や macOS などの環境で F# スクリプトを操作するときに、よりシームレスなエクスペリエンスを実現できます。

F# スクリプトは Visual StudioVisual Studio Codeでネイティブにサポートされています。

F# インタラクティブでのパッケージの参照

メモ

パッケージ管理システムは拡張可能です。 プラグインと拡張メカニズムについての詳細は、を参照してください。

言語の 5.0 リリース以降、F# インタラクティブでは拡張メカニズムを通じたパッケージの参照がサポートされています。デフォルトで、#r "nuget:" 構文と省略可能なバージョンで NuGet パッケージを参照できます。

#r "nuget: Newtonsoft.Json"
open Newtonsoft.Json

let data = {| Name = "Don Syme"; Occupation = "F# Creator" |}
JsonConvert.SerializeObject(data)

バージョンを指定しない場合は、使用可能な最上位のプレビュー版でないパッケージが取得されます。 特定のバージョンを参照するには、コンマを使用してバージョンを指定します。 これは、パッケージのプレビュー バージョンを参照するときに便利です。 たとえば、プレビュー バージョンの DiffSharp を使用する次のスクリプトを考えてみましょう。

#r "nuget: DiffSharp-lite, 1.0.0-preview-328097867"
open DiffSharp

// A 1D tensor
let t1 = dsharp.tensor [ 0.0 .. 0.2 .. 1.0 ]

// A 2x2 tensor
let t2 = dsharp.tensor [ [ 0; 1 ]; [ 2; 2 ] ]

// Define a scalar-to-scalar function
let f (x: Tensor) = sin (sqrt x)

printfn $"{f (dsharp.tensor 1.2)}"

パッケージ ソースの指定

#i コマンドを使用してパッケージ ソースを指定することもできます。 次の例では、リモートおよびローカルのソースを指定しています。

#i "nuget: https://my-remote-package-source/index.json"
#i """nuget: C:\path\to\my\local\source"""

これにより、スクリプトに追加されたリモート、ローカル、またはその両方のソースも考慮に入れるよう内部の解決エンジンに指示されます。

スクリプト内では、必要な数だけパッケージ参照を指定できます。

メモ

現在、フレームワーク参照 (Microsoft.NET.Sdk.WebMicrosoft.NET.Sdk.WindowsDesktop など) を使用するスクリプトには制限があります。 Saturn、Giraffe、WinForms などのパッケージは使用できません。 これは、イシュー #9417 で追跡されています。 WinForms は、F# インタラクティブの .NET Framework バージョンで引き続き機能します。

SDK やツールに付属する拡張機能の他に追加の拡張機能をロードするには、F# インタラクティブ セッション (またはツール設定) の引数として --compilertool:<extensionsfolderpath> フラグを使用します。

F# インタラクティブでディスク上のアセンブリを参照する

また、ディスク上にアセンブリがあり、それをスクリプト内で参照したい場合は、#r 構文を使用してアセンブリを指定できます。 MyAssembly.dll にコンパイルされるプロジェクト内の次のコードについて考えてみましょう。

// MyAssembly.fs
module MyAssembly
let myFunction x y = x + 2 * y

コンパイルしたら、Script.fsx という名前のファイル内で次のように参照できます。

#r "path/to/MyAssembly.dll"

printfn $"{MyAssembly.myFunction 10 40}"

出力は次のようになります。

dotnet fsi Script.fsx
90

スクリプト内では、必要な数だけアセンブリ参照を指定できます。

他のスクリプトの読み込み

スクリプトを作成する際は、異なるスクリプトを異なるタスク用に使用すると便利なことがよくあります。 場合によっては、あるスクリプトのコードを別のスクリプトで再利用することが必要になることがあります。 その内容をコピーしてファイルに貼り付ける代わりに、#load を使用して簡単に読み込んで評価することができます。

次の Script1.fsx を考えてみましょう。

let square x = x * x

また、これを使用するファイル Script2.fsx があります。

#load "Script1.fsx"
open Script1

printfn $"%d{square 12}"

次のように Script2.fsx を評価できます。

dotnet fsi Script2.fsx
144

スクリプト内では、必要な数だけ #load ディレクティブを指定できます。

メモ

open Script1 宣言が必要です。 これは、F# スクリプト内のコンストラクトが、それを含むスクリプト ファイルの名前である最上位レベルのモジュールにコンパイルされるためです。 スクリプト ファイルに script3.fsx などの小文字の名前がある場合は、暗黙のモジュール名が自動的に大文字化され、open Script3 を使用する必要があります。 モジュールの特定の名前空間でコンストラクトを定義する読み込み可能なスクリプトを使用する場合は、モジュール宣言の名前空間を含めることができます。次に例を示します。

module MyScriptLibrary

F# コードでの fsi オブジェクトの使用

F# スクリプトでは、F# インタラクティブ セッションを表すカスタム fsi オブジェクトにアクセスすることができます。 これにより、出力の書式設定などをカスタマイズできます。 これはコマンド ライン引数にアクセスする方法でもあります。

次の例は、コマンド ライン引数を取得して使用する方法を示しています。

let args = fsi.CommandLineArgs

for arg in args do
    printfn $"{arg}"

これを評価すると、すべての引数が出力されます。 最初の引数は、常に評価されるスクリプトの名前になります。

dotnet fsi Script1.fsx hello world from fsi
Script1.fsx
hello
world
from
fsi

同じ引数にアクセスするために System.Environment.GetCommandLineArgs() を使用することもできます。

F# インタラクティブのディレクティブのリファレンス

前述の #r および #load ディレクティブは、F# インタラクティブでのみ使用できます。 F# インタラクティブでのみ使用できるディレクティブがいくつかあります。

ディレクティブ 説明
#r "nuget:..." NuGet からパッケージを参照します
#r "extname:..." extname 拡張機能 [^1] からパッケージを参照する (paketなど)
#r "assembly-name.dll" ディスク上のアセンブリを参照します
#load "file-name.fsx" ソース ファイルを読み取り、コンパイルして実行します。
#help 特定の関数の使用可能なディレクティブまたはドキュメントに関する情報を表示します。
#I アセンブリ検索パスを引用符で囲んで指定します。
#quit F# Interactive セッションを終了します。
#time on または #time off #time 単独で、パフォーマンス情報を表示するかどうかを切り替えることができます。 onの場合には、F# Interactive は、解釈および実行されるコードの各セクションについて、リアルタイム、CPU 時間、およびガベージ コレクションの情報を測定します。

[^1]: F# インタラクティブの拡張機能についての詳細を説明します。

F# Interactive でファイルまたはパスを指定するときは、リテラル文字列が想定されます。 したがって、ファイルとパスは引用符で囲む必要があり、通常のエスケープ文字が適用されます。 @ 文字を使用して、パスを含む文字列が F# インタラクティブで逐語的文字列として解釈されるように指示することもできます。 この場合、F# Interactive はエスケープ文字を無視するようになります。

それ以外の場合、F# 9 以降の引用符は省略可能です。

拡張 #help ディレクティブ

#help ディレクティブは、特定の関数についてドキュメントの表示をサポートするようになりました。 関数の名前を直接渡して、詳細を取得できます。

#help List.map;;

出力は次のようになります。

Description:
Builds a new collection whose elements are the results of applying the given function
to each of the elements of the collection.

Parameters:
- mapping: The function to transform elements from the input list.
- list: The input list.

Returns:
The list of transformed elements.

Examples:
let inputs = [ "a"; "bbb"; "cc" ]

inputs |> List.map (fun x -> x.Length)
// Evaluates to [ 1; 3; 2 ]

Full name: Microsoft.FSharp.Collections.ListModule.map
Assembly: FSharp.Core.dll

この機能強化により、F# ライブラリを対話形式で検索し、理解するのが容易になります。

詳細については、 公式 devblogを参照してください。

対話型およびコンパイル済みのプリプロセッサ ディレクティブ

F# インタラクティブでコードをコンパイルすると、対話形式で実行しているかスクリプトを実行しているかにかかわらず、シンボル INTERACTIVE が定義されます。 コンパイラでコードをコンパイルすると、シンボル COMPILED が定義されます。 したがって、コンパイル モードと対話型モードでコードを別にする必要がある場合は、条件付きコンパイルに対する次のプリプロセッサ ディレクティブを使用して、どちらを使用するか決定することができます。 次に例を示します。

#if INTERACTIVE
// Some code that executes only in FSI
// ...
#endif

Visual Studio での F# インタラクティブの使用

Visual Studio で F# Interactive を実行するには、ツール バーの [F# Interactive] というボタンをクリックするか、Ctrl + Alt + F キーを使用します。 この操作により、対話形式のウィンドウが開きます。このウィンドウは、F# Interactive セッションを実行するツール ウィンドウです 対話形式のウィンドウで実行するコードを選択し、Alt + Enter キーの組み合わせを押す方法もあります。 F# インタラクティブが [F# Interactive] というツール ウィンドウで開始されます。 このショートカット キーを使用するときは、エディター ウィンドウにフォーカスがあることを確認します。

コンソールと Visual Studio のどちらを使用している場合でも、コマンド プロンプトが表示され、入力待ちの状態になります。 コード ファイルと同じようにコードを入力できます。 コードをコンパイルして実行するには、2 つのセミコロン (;;) を入力して、入力行を終了します。

F# Interactive によってコードがコンパイルされ、成功すると、コードが実行され、コンパイルされた型のシグネチャと値が出力されます。 エラーが発生した場合は、エラー メッセージが出力されます。

同じセッションで入力したコードからは、前に入力したどの構成要素にもアクセスできるため、プログラムの構築が可能です。 ツール ウィンドウには十分なバッファーが用意されており、必要に応じてコードをファイルにコピーできます。

Visual Studio で実行する場合、F# Interactive はプロジェクトとは独立して動作します。このため、たとえば、プロジェクトで定義された構成要素を F# Interactive で使用することはできません。使用するには、関数のコードを対話形式のウィンドウにコピーする必要があります。

設定を調整することで、F# インタラクティブのコマンド ライン引数 (省略可能) を制御できます。 [ツール] メニューの [オプション] をクリックし、[F# ツール] を展開します。 変更できる 2 つの設定は、F# Interactive オプションおよび 64 ビット コンピューターで F# Interactive を実行する場合にのみ関連する 64 ビット F# Interactive 設定です。 この設定によって、専用 64 ビット バージョンの fsi.exe を実行するか、コンピューター アーキテクチャを使用して 32 ビットまたは 64 ビットどちらのプロセスで実行するかを判断する fsianycpu.exe を実行するかを決定できます。

Title 説明
F# 対話型オプション F# インタラクティブ (fsi.exe) のコマンド ライン構文やオプションについて説明します。