Exceptions: The try...with Expression (F#)
This topic describes the try...with expression, the expression that is used for exception handling in the F# language.
The try...with expression is used to handle exceptions in F#. It is similar to the try...catch statement in C#. In the preceding syntax, the code in expression1 might generate an exception. The try...with expression returns a value. If no exception is thrown, the whole expression returns the value of expression1. If an exception is thrown, each pattern is compared in turn with the exception, and for the first matching pattern, the corresponding expression, known as the exception handler, for that branch is executed, and the overall expression returns the value of the expression in that exception handler. If no pattern matches, the exception propagates up the call stack until a matching handler is found. The types of the values returned from each expression in the exception handlers must match the type returned from the expression in the try block.
Frequently, the fact that an error occurred also means that there is no valid value that can be returned from the expressions in each exception handler. A frequent pattern is to have the type of the expression be an option type. The following code example illustrates this pattern.
Exceptions can be .NET exceptions, or they can be F# exceptions. You can define F# exceptions by using the exception keyword.
You can use a variety of patterns to filter on the exception type and other conditions; the options are summarized in the following table.
Matches the specified .NET exception type.
:? exception-type as identifier
Matches the specified .NET exception type, but gives the exception a named value.
Matches an F# exception type and binds the arguments.
Matches any exception and binds the name to the exception object. Equivalent to :? System.Exception as identifier
identifier when condition
Matches any exception if the condition is true.
The following code examples illustrate the use of the various exception handler patterns.
// This example shows the use of the as keyword to assign a name to a // .NET exception. let divide2 x y = try Some( x / y ) with | :? System.DivideByZeroException as ex -> printfn "Exception! %s " (ex.Message); None // This version shows the use of a condition to branch to multiple paths // with the same exception. let divide3 x y flag = try x / y with | ex when flag -> printfn "TRUE: %s" (ex.ToString()); 0 | ex when not flag -> printfn "FALSE: %s" (ex.ToString()); 1 let result2 = divide3 100 0 true // This version shows the use of F# exceptions. exception Error1 of string exception Error2 of string * int let function1 x y = try if x = y then raise (Error1("x")) else raise (Error2("x", 10)) with | Error1(str) -> printfn "Error1 %s" str | Error2(str, i) -> printfn "Error2 %s %d" str i function1 10 10 function1 9 2
The try...with construct is a separate expression from the try...finally expression. Therefore, if your code requires both a with block and a finally block, you will have to nest the two expressions.