大量讲解函数式编程语言的书籍最终都会用 Fuctor,Monad,Monoids, 范畴论等各种词汇吓退命令式语言玩家, 所以我试图避开这些问题, 揭开这些复杂词汇带来的具有实战意义的成果. 另外我会尽量使用 C# 语言来描述函数式编程思想, 因为 C# 某些语法和特性来自于函数式语言的启发, 但 C# 终究并不是正统的函数式语言, 随着对话题的深入, 我们不可避免要使用 F# 来描述某些特性. 所以本文会对 F# 的基础语法做一些简单了解, 本文并不是一个纯粹的 F# 教程, 只会提及必要的 F# 语法, 最终循序渐进穿插在整个文章中.
函数是一等公民
在函数式语言里, 函数被设计为一等公民, 也就是说函数跟 int, bool 等类型并没有什么区别, 例如在命令式语言的函数定义中, 参数可以是 int 值, 那么在函数式语言里, 参数也可以是一个函数. 这种特性在 C# 其实也是工作的:
public void Convert(Func<int,bool> selector){ }
这种设计在函数式语言里会有更进一步的体现:
在 F# 中声明一个简单类型用 let:
let x = 6
声明一个函数:
let f x = x + 1
或者:
let f = fun x -> x + 1
无论是申明类型还是函数, 都用 let, 这并不是一个巧合, 因为在语言设计者眼里, 函数和其他类型都是一样的.
另外需要注意, 不要看到上面的代码认为 F# 是一门动态语言, F# 毫无疑问是一门静态语言, 通过 type inference https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/type-inference 来工作. 它要比 C# 中的 var 强大的多, 只有在少数情况下需要加类型声明, 考虑下面的例子:
let stringLength x = x.Length
上面的代码并不能正常工作, 仅仅通过 x.Length 无法推断出 x 的类型, 此时需要显示标注类型:
let stringLength (x:string) = x.Length
当然你还可以向其它语言那样, 标注函数的返回值类型, 虽然此时此刻这一步并不是必须的:
let stringLength (x:string) :int = x.Length
理解 unit 类型
我们在上一篇对数学中的函数做了描述, 其中提到对于任意的输入总会有唯一的输出值与之对应, 考虑下面的代码:
let printNumber x = printf "%i" x
这段代码不论你输入什么样的 x, 它只是打印了一个数字(副作用), 他的返回值是什么? 不像 C# 中的 void,F# 会返回一个真实的类型 unit, 注意 unit 并不是 null 或者 void, 他是一个类型, 如 int 一样.
理解 tuple 类型
F# 里有一些常用的数据结构, 例如 tuple,Record types,Discriminated Union,Option,List, 不要担心, 目前你只需要知道 tuple 就可以了.
除了诸如 int, string 等类型, 如何快速的组合几个类型在一起呢? 声明一个类? 答案是: No, 比如 ("hello", 1) 就是有一个 string 和 int 组合在一起的 tuple 类型, 他的类型为 string * int. 例如下面的函数:
let sum (x, y) = x + y
它的方法签名是:
sum : x:int * y:int -> int
即函数名为 sum, 接受 int * int 类型的一个 tuple, 返回 int 类型.
如果要接受两个 int 类型的参数应该这样定义的:
let sum x y = x + y
好了, F# 的基本介绍已经完毕, 下一篇将介绍 Currying, 他是函数式编程语言中常用的模式之一, 想要继续了解的朋友继续关注下一篇.
来源: https://www.cnblogs.com/xiandnc/p/9261232.html