您的位置:首页 > 编程语言

F#程序设计-函数式编程之用函数风格来编程(2)

2009-12-21 13:17 417 查看
递归函数(Recursive Functions)

我们都知道,所谓递归函数就是函数自己调用自己,在函数式编程语言中,这是非常有用的。

在F#语言中, 定义一个递归函数,只需要在函数名前面有一个关键字rec来申明,比如下面拿一个经典的列子斐波那契数列来编写一个递归函数:

> let rec factorial x =

- if x <= 2 then

- 1

- else

- factorial (x-1) + factorial (x-2);;

val factorial : int -> int

> factorial 3;;

val it : int = 2

> factorial 10;;

val it : int = 55



在高阶函数中结合只用递归,你可以很容易地发现,在命令式编程语言中可以模拟循环结构语句到而不需要变量值。比如下面的代码中创建了两个普通的for和while循环。在这里要注意的是,在for循环中,times计数器的值是通过一个递归函数来实现的:

> let rec forLoop body times =

- if times <= 0 then

- ()

- else

- body()

- forLoop body (times - 1);;

val forLoop : (unit -> unit) -> int -> unit

> forLoop (fun () -> printfn "Looping ...") 3;;

Looping ...

Looping ...

Looping ...

val it : unit = ()



> let rec whileLoop predicate body =

- if predicate() then

- body()

- whileLoop predicate body

- else

- ();;

val whileLoop : (unit -> bool) -> (unit -> unit) -> unit

>

open System

whileLoop

(fun () -> DateTime.Now.DayOfWeek <> DayOfWeek.Saturday)

(fun () -> printfn "I wish it were the weekend...");;

I wish it were the weekend...

I wish it were the weekend...

I wish it were the weekend...





相互递归(Mutual recursion)

相互递归就是两个函数彼此相互调用对方。相互递归对于F#的类型推断来说,无疑是一个难题,因为为了确定第一个函数的类型,你需要知道第二个函数的类型, 反之亦然。

在下面的代码中,简单的编写两个函数,并且相互调用,会产生一个为定义的编译错误。从函数编程的规范来讲,在前面的函数是不能调用其后面的函数的:

> let isOdd x = if x = 1 then true else not (isEven (x -1))

- let isEven x = if x = 0 then true else not (isOdd (x-1));;

let isOdd x = if x = 1 then true else not (isEven (x -1))

-------------------------------------------^^^^^^

stdin(9,44): error FS0039: The value or constructor 'isEven' is not defined



所以,为了确定相互递归的函数能够正常工作,就必须使用关键字and,以便告诉F#编译器同时执行函数间的类型判断。下面的代码是改正后的函数:

> let rec isOdd n = (n = 1) || isEven (n - 1)

- and isEven n = (n = 0) || isOdd (n - 1);;



> isOdd 13;;

val it : bool = true



符号运算符(Symbolic Operators)

想想如果我们每次对类似1+2进行计算,不能通过+运算符而是通过自己编写的一个函数add来实现计算,那是一件多么困难的编程。幸运的是,在F#中不仅内置了像加法、减法这样的运算,还允许通过自定义运算符来实现一个更清洁、更优雅的代码。

符号运算符可以由!%&*+-./<=>?@^|~中的任意符号来表示(其中包括:只要不是第一个字符)。下面的代码定义了一个新函数!来计算数字的阶乘:

> let rec (!) x =

- if x <= 1 then 1

- else x * !(x-1);;

val ( ! ) : int -> int

> !5;;

val it : int = 120



默认情况下,当符号运算有一个以上的参数时中使用中缀表示法来表示,意思就是第一个参数在符号运算符之前,这也是使用过程中经常碰到的,比如下面的代码:

> open System.Text.RegularExpressions;;

> let (===) str (regex : string) =

- Regex.Match(str,regex).Success;;

val ( === ) : string -> string -> bool

> "The quick brown fox" === "The (.*) fox";;

val it : bool = true



符号预算符在它们的参数之前,也被称作为前缀符号,必须使用~、!、?等前缀作为函数名。在下面的代码中,函数~+++以~为前缀,并且调用时,应该写成~+++ 1 2 3而不是1 ~+++ 2 3,这样是你的符号运算函数更加的适应函数编程的风格。

> let (~+++) x y z = x + y + z;;

val ( ~+++ ) : int -> int -> int -> int

> ~+++ 1 2 3;;

val it : int = 6
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: