2012-04-03 20 views
2

我真的經常使用:如何爲finally創建新的語法塊?

try 
    try 
    with 
finally 

所以我很有趣的,如果有可能使新的語法運營商不寫「嘗試」兩次。

let mytry foo bar foobar = 
    try 
    try 
     foo 
    with 
     | _ -> bar // weird part here, I want to have a match 
    finally foobar 

mytry 
    <| foo 
    <| | :? SocketException -> 
    | _ -> // ok it looks funny but how to realize it? 
    <| foobar 

的問題,我在這裏看到的是

  • 非通用語法,在mytry沒有嘗試finally關鍵字,只是< | < | < |對於每一個,但它是較小的麻煩,我猜
  • 與:我不知道我怎麼能意識到這一部分。即使如果我能意識到它會如何看待它...

回答

3

問題是你是否真的需要try/finally。大多數時間try/finally用於處理資源,即使發生異常。但是你總是可以用use關鍵字替換它。

例如:

open System.IO 

let openFile(url: string) = 
    let fileStream = File.OpenText(url) 
    try 
     try 
      let readline = fileStream.ReadLine() 
      printfn "Readline: %s" readline 
     with 
      | :? IOException as ex -> 
        printfn "IOException: %A" ex 
      | ex -> printfn "Another exception: %A" ex 
    finally 
     fileStream.Dispose() 

可以被改寫爲:

let openFile(url: string) = 
    use fileStream = File.OpenText(url) 
    try 
     let readline = fileStream.ReadLine() 
     printfn "Readline: %s" readline 
    with 
     | :? IOException as ex -> 
       printfn "IOException: %A" ex 
     | ex -> printfn "Another exception: %A" ex 

對於學習目的,則使用高次函數可以如下定義mytry

let mytry foo bar foobar = 
    try 
    try 
     foo() 
    with 
     | exn -> bar exn 
    finally foobar() 

但上面的例子看起來不太好:

let myOpenFile(url: string) = 
    let fileStream = File.OpenText(url) 
    mytry (fun() -> let readline = fileStream.ReadLine() 
        printfn "Readline: %s" readline) 
      (fun ex -> match ex with 
        | :? IOException -> 
          printfn "IOException: %A" ex 
        | _ -> printfn "Another exception: %A" ex) 
      (fun() -> fileStream.Dispose()) 
+0

爲什麼,我喜歡看!我需要它的時候我已經有了非常複雜的邏輯,它不僅僅是用它來談論其他應用程序。也許我可以避免它,但嘗試/與/終於是我在那裏找到的最簡單的解決方案。 – Cynede 2012-04-03 11:33:34

+0

是的,這取決於個人的喜好。如果我不需要太頻繁地使用它,我更喜歡明確的'try/with/finally'來'mytry'。 – pad 2012-04-03 11:37:50

3

您可以編寫一個高階函數,將三個部分作爲單獨的函數。 try的主體將是一個函數unit -> 'R,其中'R是結果。異常處理程序只需要處理一些異常,因此您可以返回option來說明您是處理結果還是要重新排除異常。處理程序的類型將是exn -> 'R option。終結者然後只是一個功能unit -> unit

的使用並不像使用內置的語言特性優雅,但它的伎倆:

tryWithFinally 
    (fun() -> 
    1/0)         // The nested body 
    (function 
    | :? DivideByZeroException -> Some -1 // Handle division by zero 
    | _ -> None)       // Rethrow any other exceptions 
    (fun() -> 
    printfn "done") 

的實現是很容易的,一旦你知道的結構,但爲了完整起見,在這裏它是:

let tryWithFinally f handler finalizer = 
    try 
    try f() 
    with e -> 
     match handler e with 
     | Some r -> r 
     | None -> reraise() 
    finally 
    finalizer() 

反正我@pad同意,在大多數情況下,你應該罰款只有usetry .. with