为什么要用 F#

2018/09/15
原文地址: Why use F#

F# 就像其他的函数式编程语言一样,在科学计算、数据分析等领域中表现相当出色,不过使用它来进行企业级的应用开发也是一个很棒的选择。在你开始你的下一个项目之前,不妨看看下面我列出来的 5 个使用 F# 的理由。

简洁

同大多数编程语言相比,F# 代码往往不会被 “代码噪音” 扰乱,例如:花括号、分号之类的符号。

而且得益于 F# 强大的类型推断系统,你几乎不需要总是被一个对象标注类型。在解决 同一个问题 上,F# 代码与 C# 相比往往更少。

// 一行代码计算并输出列表中元素的总和
[1..100] |> List.sum |> printfn "sum=%d"

// 没有花括号、分号、圆括号
let square x = x * x
let sq = square 42

// 一行代码定义简单的类型
type Person = {First:string; Last:string}

// 稍复杂的类型也只需要两三行代码而已
type Employee =
  | Worker of Person
  | Manager of Employee list

// 类型推断系统能够自动推断 jdoe 的类型
let jdoe = {First="John";Last="Doe"}
let worker = Worker jdoe

方便

很多常见的编程任务使用 F# 来实现的话会变得非常简单,例如:创建复杂的类型、花式处理列表、定义复杂类型的相等性、实现一个状态机等等。

而且因为函数在 F# 中是一等公民,所以我们可以定义一个接受其他函数作为参数的函数,或者将使用现有的函数组合成新的函数,通过这些手段,我们就可以非常简单地来创建重用性高的代码。

// 自动地为类型定义相等性
type Person = {First:string; Last:string}
let person1 = {First="john"; Last="Doe"}
let person2 = {First="john"; Last="Doe"}
printfn "Equal? %A"  (person1 = person2)

// 使用 use 关键字来处理 IDisposable
use reader = new StreamReader(..)

// 组装函数也非常简单
let add2times3 = (+) 2 >> (*) 3
let result = add2times3 5

正确

F# 拥有一个很强大的类型系统,它可以帮助我们避免很多常见的错误,例如 空引用异常

F# 中变量默认是 不可变的(Immutable),这也能帮助我们避免很大一类错误。

除此之外,F# 的类型系统允许我们把业务逻辑使用类型来描述和约束,这样一来,想要写出错误的代码就会 相当困难

// 严格的类型检查
printfn "print string %s" 123 // 编译错误, 123 不是一个 string 类型的值

// 所有的变量都是不可变的
person1.First <- "new name"  // 编译错误,不能对不可变的变量重新赋值

// 从此不用再去检查是否为 null
let makeNewString str =
   // 变量 str 总是可以被安全的进行操作
   let newString = str + " new!"
   newString

// 将业务逻辑编写在类型之中
emptyShoppingCart.remove   // 编译错误

// 甚至可以自己定义计量单位类型
let distance = 10<m> + 10<ft> // 单位不同,不能进行运算

并发

F# 自带了大量的类库来帮助我们编写并发操作和异步操作。F# 还内置了一个 Actor 模型,我们可以用它来方便的处理系统中的事件(Event)或者编写 函数响应式风格 的代码。

当然了,因为数据结构默认都是不可变的,所以我们可以非常方便的共享数据状态而不必加锁。

// 使用 "async" 关键字可以轻松的处理异步逻辑
let! result = async {something}

// 并行运算也十分简单
Async.Parallel [ for i in 0..40 ->
      async { return fib(i) } ]

// F# 内置的消息队列
MailboxProcessor.Start(fun inbox-> async{
	let! msg = inbox.Receive()
	printfn "message is: %s" msg
	})

多范式

尽管 F# 是一门函数式语言,但是 F# 同样支持其他的那些不怎么函数式的编程范式,这使得它可以更好地与其他的非函数式的类库、应用程序和网站交互。F# 的设计混合了函数式与面向对象两种风格,所以 C# 能做的,F# 也基本上都可以做到。

F# 作为 .NET 生态系统中重要的一部分,可以无缝地去享受所有的第三方的 .NET 类库跟工具。除了 UWP 之外,所有 .NET 能够运行的平台(.Net Framework, .Net Core, Mono),F# 也能运行。

最重要的是,F# 有宇宙最强 IDE Visual Studio 的支持,智能感知、图形化调试器、单元测试工具,这些能够节省你大量开发时间的工具都是齐全的。如果你习惯使用 Linux 或者 macOS ,Rider、MonoDevelop 以及 Visual Studio Code 对 F# 也有良好的支持。

// 如果需要,你也可以让变量变得可变
let mutable counter = 0

// 创建与 C# 兼容的接口或者类
type IEnumerator<'a> =
    abstract member Current : 'a
    abstract MoveNext : unit -> bool

// F# 也支持拓展方法
type System.Int32 with
    member this.IsEven = this % 2 = 0

let i=20
if i.IsEven then printfn "'%i' is even" i

// WinForms 也可以用
open System.Windows.Forms
let form = new Form(Width= 400, Height = 300,
   Visible = true, Text = "Hello World")
form.TopMost <- true
form.Click.Add (fun args-> printfn "clicked!")
form.Show()