F# 語法概覽


F#和C#的語法差別

語法上,F#和C#有兩個主要差別:

  • 用縮進而非花括號分隔代碼塊
  • 用空白而非逗號分隔參數

F#常見語法元素

以下是F#代碼中常見的語法元素

注釋

// 這是單行注釋
(* 這是多行注釋
第二行
最后一行 *)

let 綁定

let myInt = 5
let myFloat = 3.14
let myString = "hello"

上面的語句沒有顯式指定 myInt, myFloat, myString 的類型,類型由編譯器推斷。

列表

let twoToFive = [2;3;4;5]        // 方括號表示列表,元素用分號分隔
let oneToFive = 1 :: twoToFive   // 符號 :: 將值添加到列表頭部,得到新列表,結果為 [1;2;3;4;5]
let zeroToFive = [0;1] @ twoToFive   // 符號 @ 連接兩個列表,得到新列表,結果為 [0;1;2;3;4;5]

務必注意,列表元素使用分號分隔,而非逗號分隔。

函數

命名函數用 let 關鍵字定義,匿名函數用 fun 關鍵字定義。

let square x = x * x          // 使用 let 定義命名函數,函數形參不用小括號圍住
square 3                      // 運行函數,實參也沒有小括號

let add x y = x + y           // 不可使用 (x,y)
add 2 3                       // 運行函數

// 多行函數,用縮進,不用分號
let evens list =
   let isEven x = x%2 = 0     // 內部函數
   List.filter isEven list    // List.filter 是庫函數

evens oneToFive               // 運行函數

// 用小括號指明優先級
let sumOfSquaresTo100 =
   List.sum (List.map square [1..100]) // 如果沒有小括號,那么 List.map 會是 List.sum 的參數

// 管道 |>,將操作的輸出傳給下一個操作
let sumOfSquaresTo100piped =
   [1..100] |> List.map square |> List.sum

// 用 fun 關鍵字定義拉姆達(匿名函數)
let sumOfSquaresTo100withFun =
   [1..100] |> List.map (fun x->x*x) |> List.sum

模式匹配

match..with 用於模式匹配

// 類似於 switch/case
let
simplePatternMatch = let x = "a" match x with | "a" -> printfn "x is a" | "b" -> printfn "x is b" | _ -> printfn "x is something else" // 下划線匹配任意值 // Some(..) 和 None 有點像可空類型(Nullable) let validValue = Some(99) let invalidValue = None // match..with 匹配 "Some" 和 "None",同時從 Some 中取出值 let optionPatternMatch input = match input with | Some i -> printfn "input is an int=%d" i | None -> printfn "input is missing" optionPatternMatch validValue optionPatternMatch invalidValue

復雜類型

復雜類型是指元組,記錄和聯合

// 元組,包含有序但未命名的值,值之間用逗號分隔
let twoTuple = 1,2           // 二元組
let threeTuple = "a",2,true  // 三元組

// 記錄,包含命名的字段,字段之間用分號分隔
type Person = {First:string; Last:string}
let person1 = {First="john"; Last="Doe"}

// 聯合,包含選項,選項之間用豎線分隔
type Temp = 
    | DegreesC of float
    | DegreesF of float
let temp = DegreesF 98.6

// 類型可以遞歸的組合,例如,下面的 Employee 聯合包含 Employee 類型的列表
type Employee = 
  | Worker of Person
  | Manager of Employee list
let jdoe = {First="John";Last="Doe"}
let worker = Worker jdoe

格式化輸出

 printf 和 printfn 向控制台輸出,類似於 C# Console 類的 Write 和 WriteLine 方法。sprintf 輸出到字符串,類似於 String 類的 Format 方法。

printfn "Printing an int %i, a float %f, a bool %b" 1 2.0 true
printfn "A string %s, and something generic %A" "hello" [1;2;3;4]

// 復雜類型具有內置的美觀輸出格式
printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" twoTuple person1 temp worker

let str1 = sprintf "Printing an int %i, a float %f, a bool %b" 1 2.0 true
let str2 = sprintf "A string %s, and something generic %A" "hello" [1;2;3;4]

比較F#和C#:計算平方和

C#版,不使用 linq

public static class SumOfSquaresHelper
{
   public static int Square(int i)
   {
      return i * i;
   }

   public static int SumOfSquares(int n)
   {
      int sum = 0;
      for (int i = 1; i <= n; i++)
      {
         sum += Square(i);
      }
      return sum;
   }
}

F#版

let square x = x * x
let sumOfSquares n = 
   [1..n]               // 創建 1 到 n 的列表
   |> List.map square   // 對每個元素求平方,得到新列表
   |> List.sum          // 將平方列表求和

F# 語法噪音小,沒有花括號,分號,並且在這里不需要顯式指定類型。

C#版,使用 linq

public static class FunctionalSumOfSquaresHelper
{
   public static int SumOfSquares(int n)
   {
      return Enumerable.Range(1, n)
         .Select(i => i * i)
         .Sum();
   }
}

使用 linq 改寫的 C# 代碼簡潔很多,但不能消除語法噪音,參數和返回值的類型也是必須的,仍然不如 F# 版簡潔。

例子:快速排序算法

快速排序算法的步驟是:

  1. 從列表中取出一個數作為基准
  2. 將小於基准的數放在左邊,不小於基准的數放在右邊
  3. 對基准兩邊的部分進行快速排序

下面是 F# 實現快速排序的例子

let rec quicksort list =
   match list with
   | [] -> []
   | firstElem::otherElements ->  
// 小於第一個元素的元素
let smallerElements = otherElements |> List.filter (fun e -> e < firstElem) |> quicksort

// 不小於第一個元素的元素 let largerElements = otherElements |> List.filter (fun e -> e >= firstElem) |> quicksort

// 連接成新列表
List.concat [smallerElements; [firstElem]; largerElements]
printfn "%A" (quicksort [1;5;23;18;9;1;3])

如果應用庫函數和一些技巧,代碼可壓縮成:

let rec quicksort = function
   | [] -> []                         
   | first::rest -> 
        let smaller,larger = List.partition ((>=) first) rest 
        List.concat [quicksort smaller; [first]; quicksort2 larger]

參考網站:http://fsharpforfunandprofit.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM