F#入门-第二章 F#基础-第十八节 异常(二)

    使用F#的时候,有一点特别要注意的地方,这就是,在for语句中不能退出循环。出于性能的考虑,不仅是for语句,所有循环语句,例如使用List.iter的时候,也不能退出循环。那该怎样才能退出循环呢?这种情况下,我们可以使用异常来解决这个问题。
    例如,让我们来看一个product函数,该函数接收一个整数列表,返回全部整数的乘积。我们可能会采取如下写法。

返回列表乘积的函数product
let rec product = function
    | [] -> 1
    | x::xs -> x * product xs;;
printfn "%d" (product [1..10]);;
printfn "%d" (product [0..10]);;
//如果使用高阶函数fold,可以采取如下写法。
//let product lst = List.fold_left ( * ) 1 lst;;


    稍微思考一下我们就能知道,如果列表中含有0的时候,结果为0,所以剩余的计算是不必要的。下例为如何通过传入参数来防止不必要的计算。

经过加工的函数
let product2 lst =
    let rec aux result = function
        | [] -> result
        | x::xs when x=0 -> 0
        |x::xs -> aux (x*result) xs in
    aux 1 lst;;
printfn "%d" (product2 [1..10]);;
printfn "%d" (product2 [0..10]);;



    编写函数的时候,存在着什么样的匹配模式可以象上例那样被利用,利用了该匹配模式之后程序是否能正常运行之类的问题,除此之外,当利用了for或iter等循环的时候,是不能使用以上这种利用匹配模式的写法的。这时,可以使用下例中使用异常的方法。这种使用异常的方法可以与for或iter等结合使用,使用后程序能正常运行。
    (在OCaml编程中,出于性能的考虑,存在着这种利用异常的方法。)

使用异常来省略计算
exception Prod_Result of int;;
let product3 lst=
    let rec aux = function
        | [] -> 1
        | x::xs when x=0 -> raise (Prod_Result 0)
        | x::xs -> x * (aux xs) in
        try aux lst
        with (Prod_Result 0) -> 0;;
printfn "%d" (product3 [1..10]);;
printfn "%d" (product3 [0..10]);;


    上例中的程序编写方法并不简洁明了,下例为在for语句中退出循环的例子。

for语句中抛出异常
let sum = ref 1 in
let lst = [0..10] in
let result =
try
    for i in lst do
        if i=0 then
            raise (Prod_Result 0)
        else
            sum:=!sum * i
    done;!sum
with (Prod_Result x) -> x in
printfn "%d" result;;


    虽然for语句的返回值是(),但是将for语句写在try语句中并且抛出异常,就可以返回其他类型的值了。
    这种使用异常的方法是不是可以被利用在“进行循环寻找,并且在第一个找到匹配值的地方返回”这种场合呢?  

posted @ 2010-10-12 13:55  至尊无上  阅读(574)  评论(0)    收藏  举报