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
我们都知道,所谓递归函数就是函数自己调用自己,在函数式编程语言中,这是非常有用的。
在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
相关文章推荐
- F#程序设计-函数式编程之用函数风格来编程(1)
- F#程序设计-函数式编程之函数组合(Function Composition)
- F#程序设计-函数式编程之Discriminated Unions
- F#程序设计-函数式编程之模式匹配
- F#程序设计-函数式编程之值的可变性
- 转自:Python函数式编程指南(二):函数
- Python编程基础——函数和函数式编程
- C++程序设计语言编程风格演变史
- F#程序设计-F#语言基础之函数(2)
- 函数和函数式编程
- python函数式编程内建函数filter,map,reduce函数
- <PY><core python programming笔记>C11 函数和函数式编程
- 现实世界的函数编程:有F#和C#示例
- Python学习(20):Python函数(4):关于函数式编程的内建函数
- python lambda函数 与 函数式编程
- 【Python学习笔记】函数式编程:偏函数
- python 函数、函数式编程、变量作用域、函数__doc__属性
- POJ C++程序设计 编程题#2 编程作业—多态与虚函数
- F#程序设计-F#语言基础之函数(1)
- python浓缩(11)函数和函数式编程