Как создать новый блок синтаксиса, чтобы попробовать наконец? - PullRequest
1 голос
/ 03 апреля 2012

Я действительно часто использую:

try
  try
  with
finally

, поэтому мне интересно, можно ли сделать новый синтаксический оператор, чтобы не писать "try" два раза.

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, просто <|<|<|для каждого, но это меньше проблем, я думаю, </li>
  • с: я не знаю, как я могу реализовать эту часть.даже как это будет выглядеть, если я смогу это осознать ...

Ответы [ 2 ]

2 голосов
/ 03 апреля 2012

Вы можете написать функцию высшего порядка, которая принимает три части как отдельную функцию. Тело 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, что в большинстве случаев у вас все будет в порядке с use и try .. with.

2 голосов
/ 03 апреля 2012

Вопрос в том, действительно ли вам нужно 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())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...