原文地址:http://en.wikibooks.org/wiki/F_Sharp_Programming
2. 声明函数
声明一个函数用的也是let,后面函数名和函数体,用空格间隔开来
let add x y = x + y let z = add 5 10
定义一个叫add的函数,接受两个参数,然后返回相加的结果。这里z就等于15了。
那如果我这样调用呢?
let z = add 5 10.2
也许你会说z等于15.2吧,其实这里你会得到一个错误
error FS0001: This expression was expected to have type int but here has type float
这是应该F#是一种强类型的语言,也就是说你5是一个整型,但是10.2却是浮点型。两个类型不一样,所以不能相加。如果你原来是写PHP的,或是其它弱类型的语言(相对强类型而言)。那你一定会觉得这个特性很烦。但是这也是有好处,比如说代码运行速度更快。
下面是一个稍微复杂的例子,注意最后一行的写法
let add x y = x + y let sub x y = x - y let printThreeNumbers num1 num2 num3 = printfn "num1: %i" num1 printfn "num2: %i" num2 printfn "num3: %i" num3 printThreeNumbers 5 (add 10 7) (sub 20 8)
最后一行在其它的语言里,也许是像下面这样写的,个人觉得F#的写法更省事,对于我这种懒人来说是福音。
printThreeNumbers( 5 , (add 10 7) , (sub 20 8) )
如果你像下面这样写的话,F#就会认为你传了7个参数给 printThreeNumbers 这个函数
printThreeNumbers 5 add 10 7 sub 20 8
2.1 函数返回值
不同于其它语言,在F#里你不用显示的调用return来返回值给调用者,简单的来说,函数里最后执行的语句所产生的值,就是这个函数的返回值。
let sign num = if num > 0 then "positive" elif num < 0 then "negative" else "zero"
上面所定义的函数sign,用来判断一个整数是正数还是负数,还是零。函数体内部没有显式的调用过return.但还是返回了值,也就是 positive negative zero这三个的其中一个,因为这个程序最后执行语句总是这三个分支中的其中一个。
那如果我返回不再类型的值呢,比如下面这样,最后返回的不是字符串zero而是整型0.
let sign num = if num > 0 then "positive" elif num < 0 then "negative" else 0
前面说了F#是强类型语言,和C#一样。所以这里会报错,因为你在同一个函数里,有可能返回两种不同数据类型的值。
最后要说的就是,如果一个函数没有返回值,那会怎么样,其实在F#中,如果一个函数没有返回值,它就会返回一种名为unit的类型的东西,其值为()。就是一对括号。那这个unit倒是什么,其实就相当于C语言中的void。
let helloWorld = printfn "hello world"
比如上面这行代码,printfn的作用是向终端打印东西,在这里,printfn并没有返回值,所以helloWorld的值就是(),类型为unit。
2.2 怎样读懂箭头类型提示符(Arrow Notation)
所有的函数和值在F#中都有数据类型,在函数式语言中,函数本身也可以作为值来传递。
let addAndMakeString x y = (x + y).ToString();;
val addAndMakeString : int -> int -> string
第一行你定义一个函数,然后输入;; 回车之后,F#就开始解释你这个函数了,他知道了你这个函数接受了两个参数,最后返回了一个值。于是就有了第二行的内容了。
按照箭头所指的方向,像流水一样,从左往右看。最右边的就是函数的返回值,剩下的就是函数所接受的参数。
所以在这里int -> int -> string 就表明这个函数的返回值是string,接受的参数有两个,从左向右,第一个参数是int型,第二个也是int型。再来看几个:
int -> string float -> float -> float int -> string -> float
第一行: 接受一个整型作为参数,返回字符串型。
第二行:接受一个浮点型作为第一个参数,再接受一个浮点型作为第二个参数,最后返回浮点型
第三行:接受一个整型作为第一个参数,再接受一个字符型作为第二个参数,最后返回浮点型
现在你也应该差不多理解这个东西了吧,你只要通过这个,不用看函数本身是怎么实现的,就能对这个函数明白个大概了。而F#又是怎么知道并且提示这个东西给你的呢,其实它是通过柯里化(Currying,这里取的是音译),或者叫部分求值来实现的,稍后会讲到这个。