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,
Person=%A,
Temp=%A,
Employee=%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/

原文地址:https://www.cnblogs.com/dongbeifeng/p/fsharp-syntax-overview.html