F# 互動式程式設計

使用 F# 互動 (dotnet fsi),在主控台以互動方式執行 F# 程式碼,或執行 F# 指令碼。 換句話說,F# 互動會執行 F# 的 REPL (讀取、評估、列印迴圈)。

若要從主控台執行 F# 互動,請執行 dotnet fsi。 將可以在任何 .NET SDK 中找到 dotnet fsi

注意

若要在 .NET Framework 執行階段下使用 F# 互動,您將需要安裝 Visual Studio Build Tools 或某個版本的 Visual Studio,並從開發人員命令提示字元叫用 FsiAnyCPU.exe 命令,或只要在 PATH 環境變數中將 FsiAnyCPU.exe 設定為可用,以代替 dotnet fsi 命令列。

支援定義版本 F# 互動執行階段的工具:

  • 在 Visual Studio 中:在功能表列中,[工具] / [選項],然後 [F# 工具] / [F# 互動],並調整 [使用 .NET Core 指令碼]
  • 在 Visual Studio Code (ionide 延伸模組) 中:在命令選擇區中,[喜好設定: 開啟使用者設定],然後 [延伸模組] / [F#] / [FSharp: Fsi Sdk 檔案路徑]

如需可用命令列選項的相關資訊,請參閱 F# 互動選項

直接在 F# 互動中執行程式碼

由於 F# 互動是 REPL (讀取-評估-列印迴圈),因此您可以在其中以互動方式執行程式碼。 以下是從命令列執行 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 = ()

您會注意到兩個主要事項:

  1. 所有程式碼都必須以雙分號 (;;) 終止,才可進行評估
  2. 系統會評估程式碼,並將其儲存在 it 值中。 您可以以互動方式參考 it

F# 互動也支援多行輸入。 您只需要以雙分號 (;;) 來終止提交程序。 請考慮下列已貼入 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 = ()

>

程式碼的格式會保留,而且會有雙分號 (;;) 終止輸入。 F# 互動會接著評估程式碼並列印結果!

F# 指令碼作業

在 F# 互動中以互動方式評估程式碼可謂絕佳的學習工具,但您很快就會發現,這無法像在一般編輯器中撰寫程式碼一樣有生產力。 若要支援一般程式碼編輯,您可以撰寫 F# 指令碼。

指令碼會使用副檔名 .fsx。 您只要執行 dotnet fsi,並指定 F# 原始程式碼的指令碼檔名,F# 互動就會即時讀取並執行程式碼,而不是先編譯原始程式碼,然後再執行已編譯的組件。 例如,請考量下列指令碼 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]

Visual StudioVisual Studio CodeVisual Studio for Mac 為 F# 指令碼提供原生支援。

參考 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 和/或您的工具隨附的延伸模組之外,若要載入其他延伸模組,請使用 --compilertool:<extensionsfolderpath> 旗標作為 F# 互動工作階段的引數 (或在您的工具設定中)。

使用 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# 指令碼可存取自訂 fsi 物件,該物件代表 F# 互動工作階段。 其可讓您自訂輸出格式等項目。 這也是您可以存取命令列引數的方式。

下列範例示範如何取得和使用命令列引數:

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 會自行切換是否顯示效能資訊。 當 F# 互動為 "on" 時,其會針對每個已解譯和執行的程式碼區段,測量即時、CPU 時間和記憶體回收資訊。

[^1]:深入了解 F# 互動延伸模組 (英文)。

當您在 F# Interactive 中指定檔案或路徑時,應該要有一個字串常值。 因此,檔案和路徑必須以引號括住,並遵循一般的逸出字元。 您可以使用 @ 字元,讓 F# 互動將包含路徑的字串解譯為逐字字串。 這會導致 F# Interactive 會忽略所有逸出字元。

互動式和已編譯的前置處理器指示詞

當您編譯 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# Interactive 會隨即在標示為 F# Interactive 的工具視窗中啟動。 當您使用這個按鍵組合時,請確定編輯器視窗具有焦點。

不論是使用主控台還是否 Visual Studio,命令提示字元都會出現,表示解譯器在等待您輸入。 您可以如同在程式碼檔案中一樣輸入程式碼。 若要編譯並執行程式碼,請輸入兩個分號 (;;) 以終止一或數行的輸入。

F# Interactive 會嘗試編譯程式碼,如果成功的話,它會執行程式碼,並列印它所編譯的類型與值的簽章。 如果發生錯誤,解譯器就會列印錯誤訊息。

在同一個工作階段中輸入的程式碼,可以存取先前輸入的所有建構,因此您可以建置程式。 若有需要,可利用 [工具] 視窗中的延伸緩衝區,視需要將程式碼複製到檔案。

在 Visual Studio 中執行 F# Interactive 時,會與專案分開執行,因此,舉例來說,除非您將函式的程式碼複製到 [互動] 視窗,否則無法使用在 F# Interactive 中專案內所定義的建構。

您可以調整設定來控制 F# 互動命令列引數 (選項)。 在 [工具] 功能表上,選取 [選項...],然後展開 [F# 工具]。 您只能變更 F# Interactive 選項和 [64 位元 F# Interactive] 這兩項設定,而且只有在 64 位元電腦上執行 F# Interactive 時才相關。 這項設定會判斷您要執行專用的 64 位元版 fsi.exefsianycpu.exe,其會使用機器結構來判斷要以 32 位元或 64 位元的處理序執行。

標題 描述
F# Interactive 選項 說明 F# 互動 (fsi.exe) 的命令列語法與選項。