This is a F# Tutorial.

open System                        // 这步操作可以让我们使用 .NET Core 的函数库
open System.Drawing

let hello() =                      // let 用来绑定函数名或者参数名
  printf "Enter your name: "     // printf 不启用新行的打印函数
    
  let name = Console.ReadLine()  // 读取一行并将读取到的值和 name 绑定

  printfn "Hello %s!" name       // 启用新行的打印 % 引用参数
  // %s %i %f %b %A %O           

hello()

let hello1() =
  printfn "PI: %f" 3.14159265358979323846264338327       // 浮点数只有6位小数
  printfn "PI: %.4f" 3.14159265358979323846264338327     // 可以调整显示的小数的位数
  printfn "Big PI: %M" 3.14159265358979323846264338327M  // 最高可以到达27位小数

hello1()

let hello2() =
  printfn "%-5s %5s" "a" "b"             // 添加空格
  printfn "%*s" 10 "Hi"                  // 动态空格
    
hello2()

let bindStuff() =
  let mutable weight = 175         // 可以改变的参数 (mutable)
  weight <- 170                    // 使用 <- 赋值
  
  printfn "Weight: %i" weight

  let changeMe = ref 10            // 奇怪的语法,先不管这了
  changeMe := 50

  printfn "Change: %i" ! changeMe

bindStuff()

let doFuns() =
  let getSum(x : int, y : int) :int = x + y

  printfn "5 + 7 = %i" (getSum(5,7))

  // 递归函数
  let rec factorial x =
    if x < 1 then 1
    else x * factorial (x - 1)
  
  printfn "Factorial 4 : %i" (factorial 4)
  // 1st : result = 4 * factoral(3) = 4 * 6 = 24
  // 2st : result = 3 * factoral(2) = 3 * 2 = 6
  // 1st : result = 2 * factoral(1) = 2 * 1 = 2

  // 定义一个列表 (List)
  let randList = [1; 2; 3]
  // map 可以对数组里的每一个元素进行特定操作,
  // 第一个参数是 lambda 表达式 (anonymous function, 匿名函数)
  // 第二个参数是被操作的数组
  let randList2 =  List.map (fun x -> x * 2) randList
  printfn "Double List : %A" randList2

  // 管道可以很方便地进行多步计算
  // 管道:将值输入(|>)到函数中
  [5; 6; 7; 8]
  |> List.filter (fun v -> (v % 2) = 0)
  |> List.map (fun x -> x * 2)
  |> printfn "Even Doubles %A" 

  // >> 和 << 可以将两个函数合二为一
  let multNum x = x * 3
  let addNum y = y + 5

  let multAdd = multNum >> addNum
  let addMult = multNum << addNum

  printfn "multAdd : %i" (multAdd 10)
  printfn "addMult : %i" (addMult 10)

doFuns()

// 一些数学函数
let doMath() =
  printfn "5 + 4 = %i" (5 + 4)
  printfn "5 - 4 = %i" (5 - 4)
  printfn "5 * 4 = %i" (5 * 4)
  printfn "5 / 4 = %i" (5 / 4)
  // "" 里面用 % 要用 %%
  printfn "5 %% 4 = %i" (5 % 4)
  // 5^2
  printfn "5 ** 2 = %f" (5.0 ** 2.0)

  let number = 2
  printfn "Type: %A" (number.GetType())
  printfn "A Float: %.2f" (float number)
  printfn "An Int: %i" (int 3.14)

  // 其他数学函数
  // 绝对值
  printfn "abs 4.5 : %i" (abs -1)
  // 向上取整
  printfn "ceil 4.5 : %f" (ceil 4.5)
  // 向下取整
  printfn "floor 4.5 : %f" (floor 4.5)
  // ln
  printfn "log 2.71828 : %f" (log 2.71828)
  // lg
  printfn "log10 1000 : %F" (log10 1000.0)
  // 求平方根
  printfn "sqrt 25 : %f" (sqrt 25.0)


doMath()

let stringStuff() =
  let str1 = "This is a random string\\"
  // @ 加到字符串之前可以将 \ 加入到字符串之中
  let str2 = @"I ignore backslashes\\\\"
  // 三个双引号可将引号添加到字符串
  let str3 = """ "I ignore qutes and backslashes" """
  // 字符串相连
  let str4 = str1 + " " + str2
  // length 获取字符串的长度
  printfn "Length : %i" (String.length str4)
  // 和 C 相似的字符访问
  printfn "%c" str1.[1]
  // 和 Python 相似的字符串切片操作
  printfn "First word : %s" (str1.[..3])
  printfn "Second word : %s" (str1.[5..6])
  printfn "The rest word : %s" (str1.[8..])

  // 
  let upperStr = String.collect (fun c -> sprintf "%c, " c) "commas"
  printfn "Commas : %s" upperStr

  // 测试字符串中是否有字符满足条件
  printfn "Any upper: %b" (String.exists (fun c -> Char.IsUpper c) str1)

  // 测试字符串中所有的字符满足条件
  printfn "Number : %b" (String.forall (fun c -> Char.IsDigit c) "1234")

  // 初始化字符串
  let string1 = String.init 10 (fun i -> i.ToString() )
  printfn "Numbers : %s" string1

  // 对字符串中的每个字符进行操作
  String.iter (fun c -> printfn "%c" c) "Print Me!"

stringStuff()

let loopStuffWhile() =
  let magic_num = "7"
  let mutable guess = ""

  while not (magic_num.Equals(guess)) do
    printf "Guess the Number :"
    guess <- Console.ReadLine()

  printfn "You Guessed the Number!"

loopStuffWhile()

let loopStuffFor() = 
  for i = 1 to 10 do 
    printfn "%i" i

  for i = 10 downto 1 do
    printfn "%i" i

  for i in [1..10] do
    printfn "%i" i

  [1..10] |> List.iter (printfn "Num : %i")

  let sum = List.reduce (+) [1..10]
  printfn "Sum : %i" sum

loopStuffFor()

let cond_stuff() =
  let age = 8

  if age < 5 then
    printfn "Preschool"
  elif age = 5 then
    printfn "Kindergarten"
  elif (age > 5) && (age <= 18) then
    let grade = age - 5
    printfn "Go to grade %i" grade
  else
    printfn "Go to College"

  let gpa = 3.9
  let income = 15000

  printfn "College Grant: %b" ((gpa >= 3.8) || (income <= 12000))

  printfn "Not True: %b" (not true)

  let grade2: string =
    match age with
    | age when age < 5 -> "Preschool"
    | 5 -> "Kindergaten"
    | age when ((age > 5) && (age <= 18)) -> (age - 5).ToString()
    | _ -> "Collage"

  printfn "Grade2 : %s" grade2

cond_stuff()

let list_stuff() =

  let list1 = [1; 2; 3; 4]
  list1 |> List.iter (printfn "Num : %i")
  printfn "list1 : %A" list1

  let list2 = 5::6::7::[]
  printfn "list2 : %A" list2 

  let list3 = [1..5]
  printfn "list : %A" list3

  let list4 = ['a'..'g']
  printfn "list4 : %A" list4

  let list5 = List.init 5 (fun i -> i * 2)
  printfn "list5 : %A" list5

  let list6 = [for a in 1..5 do yield (a * a)]
  printfn "list6 : %A" list6

  let list7 = [for a in 1..20 do if a % 2 = 0 then yield a]
  printfn "list7 : %A" list7

  let list8 = [for a in 1..3 do yield! [a..a + 2]]
  printfn "list8 : %A" list8

  printfn "Length : %i" list8.Length
  printfn "Empty : %b" list8.IsEmpty
  printfn "Index 2 : %c" (list4.Item(2))
  printfn "Head : %c" (list4.Head)
  printfn "Tail : %A" (list4.Tail)

  let list9 = list3 |> List.filter (fun x -> x % 2 = 0)

  let list10 = list9 |> List.map (fun x -> (x * x))

  printfn "Sorted : %A" (List.sort [5; 4; 3])

  printfn "Sum : %i" (List.fold (fun sum elem -> sum + elem) 0 [1; 2; 3])

list_stuff()

type emotion =
| joy = 0
| fear = 1
| anger = 3

let enum_stuff() =
  let myFeeling = emotion.joy

  match myFeeling with
  | joy -> printfn "I'm joyful"
  | fear -> printfn "I'm fearful"
  | anger -> printfn "I'm angry"

enum_stuff()

let optionStuff() =
  let divide x y =
    match y with
    | 0 -> None
    | _ -> Some(x / y)

  if (divide 5 0).IsSome then
    printfn "5/0 = %A" ((divide 5 0).Value)
  elif (divide 5 0).IsNone then
    printfn "Can't Divide by Zero"
  else
    printfn "Something happenend"

optionStuff()

let tupleStuff() =
  let avg (w, x, y, z) : float =
    let sum = w + x + y + z
    sum / 4.0

  printfn "Avg : %f" (avg (1.0, 2.0, 3.0, 4.0))

  let my_data = ("luo", 22, 6.25)

  let (name, age, _) = my_data

  printfn "Name : %s, age : %i" name age

tupleStuff()

type customer =
  {Name : string;
   Blance : float}

let recordStuff() = 
  let bob = {Name = "Bob Smith"; Blance = 101.5012}
  printfn "%s owes us %.2f" bob.Name bob.Blance

recordStuff()

let seqStuff() = 
  let seq1 = seq {1..100}
  let seq2 = seq {0..2..50}
  let seq3 = seq {50..1}

  printfn "%A" seq2

  Seq.toList seq2 |> List.iter (printfn "Num : %i")

  let isPrime n =
    let rec check i =
      i > (n / 2) || (n % i <> 0 && check (i + 1))
    check 2

  let prime_seq = seq {for n in 1..500 do if isPrime n then yield n}

  printfn "%A" prime_seq

  Seq.toList prime_seq |> List.iter (printfn "Prime : %i")
  
seqStuff()

let mapStuff() =
  let customers =
    Map.empty.
      Add("Bob Smith", 100.50).
      Add("Sally Marks", 50.25)

  printfn "# of Customers %i" customers.Count

  let cust = customers.TryFind "Bob Smith"
  match cust with
  | Some x -> printfn "Balace : %.2f" x
  | None -> printfn "Not Found"

  printfn "Customer : %A" customers

  if customers.ContainsKey "Bob Smith" then
    printfn "Bob Smith was found"

  printfn "Bobs Blance : %.2f" customers.["Bob Smith"]

  let custs2 = Map.remove "Sally Marks" customers

  printfn "# of Customers %i" custs2.Count

mapStuff()

let addStuff<'T> x y =
  printfn "%A" (x + y)

let genericStuff() =
  addStuff<float> 5.5 2.4
  // addStuff<int> 4 2

genericStuff()

let expStuff() =
  let divideFloat x y =
    try 
      printfn "%.2f / %.2f = %.2f" x y (x / y)
    with 
      | :? System.DivideByZeroException as ex ->
        printfn "Can't Divide by Zero"
  divideFloat 5.0 0.0

  let divideInt x y =
    try 
      printfn "%i / %i = %i" x y (x / y)
    with 
      | :? System.DivideByZeroException as ex ->
        printfn "Can't Divide by Zero"
  divideInt 5 0

  let divideIntR x y =
    try 
      if y = 0 then raise(DivideByZeroException "Can't Divide by 0")
      else
        printfn "%i / %i = %i" x y (x / y)
    with 
      | :? System.DivideByZeroException as ex ->
        printfn "Can't Divide by Zero"
  divideIntR 5 0

expStuff()

type Rectangle = struct
  val Length : float
  val Width : float
  new (length, width) =
    {Length = length; Width = width;}
end

let structStuff() =
  let area(shape: Rectangle) =
    shape.Length * shape.Width

  let rect = new Rectangle(5.0, 6.0)

  let rect_area = area rect

  printfn "Area : %.2f" rect_area

structStuff()

type Animal = class
  val Name : string
  val Height : float
  val Weight : float

  new (name, height, weight) =
    {Name = name; Height = height; Weight = weight;}

  member x.Run =
    printfn "%s Runs" x.Name
end

type Dog(name, height, weight) =
  inherit Animal(name, height, weight)

  member x.Bark = 
    printfn "%s Barks" x.Name

let classStuff() =
  let spot = new Animal("Spot", 20.5, 40.5)
  spot.Run

  let bowser = new Dog("Bowser", 20.5, 40.5)
  bowser.Run
  bowser.Bark

classStuff()

Console.ReadKey() |> ignore        // 输入一个字符防止命令行一闪而过

Gist: