F# syntax in 60 seconds

https://swlaschin.gitbooks.io/fsharpforfunandprofit/content/posts/fsharp-in-60-seconds.html

下面是一个关于如何阅读F#代码的非常快速的概述,供不熟悉语法的新人参考。

这显然不是很详细,但应该足够了,这样你就可以阅读并掌握本系列中即将到来的例子的要点。如果你不理解所有的内容,也不用担心,因为当我们看到实际的代码例子时,我会给出更详细的解释。

F# 语法和标准的类 C 语法之间的两个主要区别是:

  • 大括号不用于分隔代码块。相反,使用缩进(Python 与此类似)。

  • 空格用于分隔参数而不是逗号。

有些人觉得F#的语法让人不舒服。如果你是其中之一,请考虑这句话:

"Optimising your notation to not confuse people in the first 10 minutes of seeing it but to hinder readability ever after is a really bad mistake." (David MacIver, via a post about Scala syntax).

"如果通过优化你的符号系统,使人们在看到它的前10分钟不会感到困惑,但之后却阻碍了可读性,这是一个非常糟糕的错误。" (David MacIver,通过一篇关于Scala语法的文章)。

我个人认为,当你习惯了F#的语法后,它是非常清晰和直接的。在许多方面,它比C#的语法更简单,有更少的关键字和特殊情况。

下面的示例代码是一个简单的F#脚本,演示了你经常需要的大部分概念。

我鼓励您以交互式测试此代码并尝试一下!任何一个:

  • 将其键入 F# 脚本文件(扩展名为 .fsx)并将其发送到交互式窗口。有关详细信息,请参阅“安装和使用 F#”页面。

  • 或者,尝试在交互式窗口中运行这段代码。记住在结尾处一定要使用;;来告诉解释器你已经完成了输入并准备进行执行。

// single line comments use a double slash
(* multi line comments use (* . . . *) pair

-end of multi line comment- *)

// ======== "Variables" (but not really) ==========
// The "let" keyword defines an (immutable) value
let myInt = 5
let myFloat = 3.14
let myString = "hello"    //note that no types needed

// ======== Lists ============
let twoToFive = [2;3;4;5]        // Square brackets create a list with
                                 // semicolon delimiters.
let oneToFive = 1 :: twoToFive   // :: creates list with new 1st element
// The result is [1;2;3;4;5]
let zeroToFive = [0;1] @ twoToFive   // @ concats two lists

// IMPORTANT: commas are never used as delimiters, only semicolons!

// ======== Functions ========
// The "let" keyword also defines a named function.
let square x = x * x          // Note that no parens are used.
square 3                      // Now run the function. Again, no parens.

let add x y = x + y           // don't use add (x,y)! It means something
                              // completely different.
add 2 3                       // Now run the function.

// to define a multiline function, just use indents. No semicolons needed.
let evens list =
   let isEven x = x%2 = 0     // Define "isEven" as an inner ("nested") function
   List.filter isEven list    // List.filter is a library function
                              // with two parameters: a boolean function
                              // and a list to work on

evens oneToFive               // Now run the function

// You can use parens to clarify precedence. In this example,
// do "map" first, with two args, then do "sum" on the result.
// Without the parens, "List.map" would be passed as an arg to List.sum
let sumOfSquaresTo100 =
   List.sum ( List.map square [1..100] )

// You can pipe the output of one operation to the next using "|>"
// Here is the same sumOfSquares function written using pipes
let sumOfSquaresTo100piped =
   [1..100] |> List.map square |> List.sum  // "square" was defined earlier

// you can define lambdas (anonymous functions) using the "fun" keyword
let sumOfSquaresTo100withFun =
   [1..100] |> List.map (fun x->x*x) |> List.sum

// In F# returns are implicit -- no "return" needed. A function always
// returns the value of the last expression used.

// ======== Pattern Matching ========
// Match..with.. is a supercharged case/switch statement.
let simplePatternMatch =
   let x = "a"
   match x with
    | "a" -> printfn "x is a"
    | "b" -> printfn "x is b"
    | _ -> printfn "x is something else"   // underscore matches anything

// Some(..) and None are roughly analogous to Nullable wrappers
let validValue = Some(99)
let invalidValue = None

// In this example, match..with matches the "Some" and the "None",
// and also unpacks the value in the "Some" at the same time.
let optionPatternMatch input =
   match input with
    | Some i -> printfn "input is an int=%d" i
    | None -> printfn "input is missing"

optionPatternMatch validValue
optionPatternMatch invalidValue

// ========= Complex Data Types =========

// Tuple types are pairs, triples, etc. Tuples use commas.
let twoTuple = 1,2
let threeTuple = "a",2,true

// Record types have named fields. Semicolons are separators.
type Person = {First:string; Last:string}
let person1 = {First="john"; Last="Doe"}

// Union types have choices. Vertical bars are separators.
type Temp = 
    | DegreesC of float
    | DegreesF of float
let temp = DegreesF 98.6

// Types can be combined recursively in complex ways.
// E.g. here is a union type that contains a list of the same type:
type Employee = 
  | Worker of Person
  | Manager of Employee list
let jdoe = {First="John";Last="Doe"}
let worker = Worker jdoe

// ========= Printing =========
// The printf/printfn functions are similar to the
// Console.Write/WriteLine functions in C#.
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]

// all complex types have pretty printing built in
printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" 
         twoTuple person1 temp worker

// There are also sprintf/sprintfn functions for formatting data
// into a string, similar to String.Format.

然后,让我们开始比较一些简单的 F# 代码和等效的 C# 代码。

(后面先翻译The "Thinking Functionally" Series,现在的东西过于没用了,大量东西都是强时效性的,好多库都无人维护,翻译了也没有价值,先去翻译和语言设计本身有关的东西了)

Last updated