Async.Await not catching Task exception - exception

I have a Task that does not return anything. You can't do an Async.AwaitTask on such a Task, so you need to do an Async.AwaitIAsyncTask instead. Unfortunately this seems to just swallow any exceptions that the underlying Task throws out: -
TaskFactory().StartNew(Action(fun _ -> failwith "oops"))
|> Async.AwaitIAsyncResult
|> Async.Ignore
|> Async.RunSynchronously
// val it : unit = ()
On the other hand, AwaitTask correctly cascades the exception: -
TaskFactory().StartNew(fun _ -> failwith "oops"
5)
|> Async.AwaitTask
|> Async.Ignore
|> Async.RunSynchronously
// POP!
What's the best way of treating regular (non-generic) Tasks as Async yet still get propagation of exceptions?

As an option that will properly handle cancellation:
open System.Threading.Tasks
module Async =
let AwaitTask (t: Task) =
Async.FromContinuations(fun (s, e, c) ->
t.ContinueWith(fun t ->
if t.IsCompleted then s()
elif t.IsFaulted then e(t.Exception)
else c(System.OperationCanceledException())
)
|> ignore
)

From the Xamarin F# Shirt App (which I originally borrowed from Dave Thomas):
[<AutoOpen>]
module Async =
let inline awaitPlainTask (task: Task) =
// rethrow exception from preceding task if it faulted
let continuation (t : Task) = if t.IsFaulted then raise t.Exception
task.ContinueWith continuation |> Async.AwaitTask

Related

How to assert that a function throws an exception?

I can catch exceptions:
try some_fn () with | e -> print_endline "exception caught!"
but what about the other way around, detecting that a function does not throw an exception (when it should)?
I managed to write some very hacky way to achieve that: I create a wrapper around the function I want to test, which throws some specific exception at the end. I catch anything but that exception.
exception Finished
let check (fn : unit -> unit) =
let wrapper _ = (
fn ();
raise Finished)
in
try wrapper () with e when e <> Finished -> ()
in utop this works:
utop # check (fun _ -> ());;
Exception: Finished.
utop # check (fun _ -> failwith "hey");;
- : unit = ()
EDIT: my coworker suggested:
let should_fail fn =
if Result.try_with fn |> Result.is_ok then failwith "this test should fail"
Exceptions can be handled within pattern matching cases, allowing very clean expression for this check:
match some_fn () with
| exception _ -> print_endline "exception caught!"
| _ -> print_endline "error: no exception raised!"
We can abstract this check into a function:
let throws_exception f =
match f () with
| exception _ -> true
| _ -> false
Which we can use in an assertion like so:
assert (throws_exception (fun () -> raise (Failure "msg")))

Handling and printing exceptions with SML

I have a code that looks quite like:
ignore
(f ())
handle
AssertionError msg => (print ("assertion error: " ^ msg ^ "\n"); ())
| _ (* other exceptions *) => (print ("exception raised\n"); ())
But I need to print the generic exception message (with exnMessage?).
How do I catch the _ exception in order to get and print its message?
Match the exception with a name instead of _ and use exnMessage:
- (hd ([]: string list)) handle e => exnMessage e;
val it = "Empty" : string

F# exception handling multiple "Tries"

I'm trying to read a bunch of csv files in SQL Server using SQL Bulk Insert and DataContext.ExecuteCommand. (Maybe this isn't the best way to do it, but it does allow me stay in the Type Provider context--as opposed to with SqlBulkCopy I think.) Now the upload is glitchy with intermittent success. Some files read in, some fail with "Data conversion error (truncation)". I think this has to do with the row terminators not always working.
When the upload works, it seems to be with the '0x0A' terminator. But when that fails, I want to try repeatedly again with other row terminators. So I want to go into a Try statement, and on failure go into another Try statement, and another if that one fails, ... . This may not be the best way to upload, but I am still curious about the Try logic for it's own state.
Here's what I've come up with so far and it's not too pretty (but it works). Cutting out a few nested layers:
let FileRead path =
try
db.DataContext.ExecuteCommand(#"BULK INSERT...ROWTERMINATOR='0x0A')") |> ignore
true
with
| exn ->
try
db.DataContext.ExecuteCommand(#"BULK INSERT...ROWTERMINATOR='\r')") |> ignore
true
with
| exn ->
try
db.DataContext.ExecuteCommand(#"BULK INSERT...ROWTERMINATOR='\n')") |> ignore
true
with
| exn ->
false
This doens't feel right but I haven't figured out any other syntax.
EDIT: What I ended up doing, just for the record. Appreciate being put on a productive path. There's plenty to improve in this. With one of the more significant things being to use Async's and run it Parallel (which I have gotten experience with in other sections).
type dbSchema = SqlDataConnection<dbConnection>
let db = dbSchema.GetDataContext()
let TryUpLd table pathFile rowTerm =
try
db.DataContext.ExecuteCommand( #"BULK INSERT " + table + " FROM '" + pathFile +
#"' WITH (FIELDTERMINATOR=',', FIRSTROW = 2, ROWTERMINATOR='"
+ rowTerm + "')" ) |> ignore
File.Delete (pathFile) |> Some
with
| exn -> None
let NxtUpLd UL intOpt =
match intOpt with
| None -> UL
| _ -> intOpt
let MoveTable ID table1 table2 =
//...
()
let NxtMoveTable MT intOpt =
match intOpt with
| Some i -> MT
| _ -> ()
let UpLdFile path (file:string) =
let (table1, table2) =
match path with
| p when p = dlXPath -> ("Data.dbo.ImportXs", "Data.dbo.Xs")
| p when p = dlYPath -> ("Data.dbo.ImportYs", "Data.dbo.Ys")
| _ -> ("ERROR path to tables", "")
let ID = file.Replace(fileExt, "")
let TryRowTerm = TryUpLd table1 (path + file)
TryRowTerm "0x0A"
|> NxtUpLd (TryRowTerm "\r")
|> NxtUpLd (TryRowTerm "\n")
|> NxtUpLd (TryRowTerm "\r\n")
|> NxtUpLd (TryRowTerm "\n\r")
|> NxtUpLd (TryRowTerm "\0")
|> NxtMoveTable (MoveTable ID table1 table2)
let UpLdData path =
let dir = new DirectoryInfo(path)
let fileList = dir.GetFiles()
fileList |> Array.iter (fun file -> UpLdFile path file.Name ) |> ignore
Here's one way to do it, using monadic composition.
First, define a function that takes another function as input, but converts any exception to a None value:
let attempt f =
try f () |> Some
with | _ -> None
This function has the type (unit -> 'a) -> 'a option; that is: f is inferred to be any function that takes unit as input, and returns a value. As you can see, if no exception happens, the return value from invoking f is wrapped in a Some case. The attempt function suppresses all exceptions, which you shouldn't normally do.
Next, define this attemptNext function:
let attemptNext f = function
| Some x -> Some x
| None -> attempt f
This function has the type (unit -> 'a) -> 'a option -> 'a option. If the input 'a option is Some then it's simply returned. In other words, the value is interpreted as already successful, so there's no reason to try the next function.
Otherwise, if the input 'a option is None, this is interpreted as though the previous step resulted in a failure. In that case, the input function f is attempted, using the attempt function.
This means that you can now compose functions together, and get the first successful result.
Here are some functions to test with:
let throwyFunction () = raise (new System.InvalidOperationException("Boo"))
let throwyFunction' x y = raise (new System.InvalidOperationException("Hiss"))
let goodFunction () = "Hooray"
let goodFunction' x y = "Yeah"
Try them out in F# Interactive:
> let res1 =
attempt throwyFunction
|> attemptNext (fun () -> throwyFunction' 42 "foo")
|> attemptNext goodFunction
|> attemptNext (fun () -> goodFunction' true 13.37);;
val res1 : string option = Some "Hooray"
> let res2 =
attempt goodFunction
|> attemptNext throwyFunction
|> attemptNext (fun () -> throwyFunction' 42 "foo")
|> attemptNext (fun () -> goodFunction' true 13.37);;
val res2 : string option = Some "Hooray"
> let res3 =
attempt (fun () -> throwyFunction' 42 "foo")
|> attemptNext throwyFunction
|> attemptNext (fun () -> goodFunction' true 13.37)
|> attemptNext goodFunction;;
val res3 : string option = Some "Yeah"
> let res4 =
attempt (fun () -> throwyFunction' 42 "foo")
|> attemptNext (fun () -> goodFunction' true 13.37)
|> attemptNext throwyFunction
|> attemptNext goodFunction;;
val res4 : string option = Some "Yeah"

Defining and Catching Exceptions

I'm still getting the hang of haskell, and am trying to build my first "real" coding project, i.e. one where I'm going to including testing, write up documentation, etc. I'm sufficiently new to haskell where I know I don't have a lot of the knowledge of the language necessary so that everything I want to do is immediately within reach, but that's kind of the idea, so that the act of finishing will require that I touch most of the major pieces of the language.
Anyway, so the current issue I'm having is regarding throwing and catching exceptions in the language, something that I understand can be done with quite varied approaches. I have a function here, toLower:
toLower :: String -> String
toLower plaintext =
if (catch (nonAlpha plaintext) handlerNonAlpha)
then map charToLower plaintext
else exitFailure
Which will take a string, throw an exception and exit if the string includes any non-alpha characters (so if not A-Z or a-z), or if not convert the string to lowercase. So what I have for the nonAlpha function is:
--- detect non-alpha character - throw error if existant
data NonNumericException = NonNumException
instance Exception NonNumericException
handlerNonAlpha :: NonNumericException -> IO()
handlerNonAlpha ex =
putStrLn "Caught Exception: " ++ (show ex) ++ " - A non-alpha character was included in the plaintext."
nonAlpha :: String -> Bool
nonAlpha str =
let nonalphas = [x | x <- str, (ord x) < 65 || (90 < (ord x) && (ord x) < 97) || 123 < (ord x)]
in if (length nonalphas) == 0
then True
else throw NonNumException
As I said I'm pretty new to haskell, so I'm a little vague on how this data/instance structure works, but as I understand it I'm defining an parent NonNumericException, of which NonNumException is a child (and I could have more), and in the instance line defining them to be Exceptions. The catch structure, if it detects an exception (for instance, when one is thrown at the end of nonAlpha if there is a non-alpha character), then calls the handler.
So here are the compile errors that I get:
utilities.hs:61:3:
Couldn't match expected type `[Char]' with actual type `IO ()'
In the return type of a call of `putStrLn'
In the first argument of `(++)', namely
`putStrLn "Caught Exception: "'
In the expression:
putStrLn "Caught Exception: "
++
(show ex)
++ " - A non-alpha character was included in the plaintext."
utilities.hs:61:3:
Couldn't match expected type `IO ()' with actual type `[Char]'
In the expression:
putStrLn "Caught Exception: "
++
(show ex)
++ " - A non-alpha character was included in the plaintext."
In an equation for `handlerNonAlpha':
handlerNonAlpha ex
= putStrLn "Caught Exception: "
++
(show ex)
++ " - A non-alpha character was included in the plaintext."
utilities.hs:73:7:
Couldn't match expected type `Bool' with actual type `IO ()'
In the return type of a call of `catch'
In the expression: (catch (nonAlpha plaintext) handlerNonAlpha)
In the expression:
if (catch (nonAlpha plaintext) handlerNonAlpha) then
map charToLower plaintext
else
exitFailure
utilities.hs:73:14:
Couldn't match expected type `IO ()' with actual type `Bool'
In the return type of a call of `nonAlpha'
In the first argument of `catch', namely `(nonAlpha plaintext)'
In the expression: (catch (nonAlpha plaintext) handlerNonAlpha)
utilities.hs:75:8:
Couldn't match type `IO a0' with `[Char]'
Expected type: String
Actual type: IO a0
In the expression: exitFailure
In the expression:
if (catch (nonAlpha plaintext) handlerNonAlpha) then
map charToLower plaintext
else
exitFailure
In an equation for `toLower':
toLower plaintext
= if (catch (nonAlpha plaintext) handlerNonAlpha) then
map charToLower plaintext
else
exitFailure
So I guess my two question are, a) what's going wrong with the types for the handler (the line 61 errors), and b) how do I properly set the types for the functions that may throw an exception or exit with failure, but otherwise will return a bool or a string?
EDIT: I guess I should note. I do see the similarities between this question and a number of others that have been asked. Part of what I'm looking for that I don't see is a description of what the structures here are actually doing, and what is best practice and why.
What is best practice in Haskell is to leverage the awesome power of its type system to avoid needing to throw/catch exceptions for pure functions. There are cases where throwing an exception can actually make sense, but for something like your toLower function you can just choose to have a different return type. For example:
-- We can factor out our check for a non-alpha character
isNonAlpha :: Char -> Bool
isNonAlpha c = c' < 65 || (90 < c' && c' < 97) || 123 < c'
where c' = ord c
-- Why throw an exception? Just return False
hasNonAlpha :: String -> Bool
hasNonAlpha str = any isNonAlpha str
-- Renamed to not conflict with Data.Char.toLower
myToLower :: String -> Maybe String
myToLower plaintext =
if hasNonAlpha plaintext
then Nothing
else Just $ map toLower plaintext
Not only is this cleaner code, but now we don't have to worry about error handling at all, and someone else using your code won't get a nasty surprise. Instead, the notion of failure is encoded at the type level. To use this as an "error handling" mechanism, just work in the Maybe monad:
doSomething :: String -> String -> Maybe String
doSomething s1 s2 = do
s1Lower <- myToLower s1
s2Lower <- myToLower s2
return $ s1Lower ++ s2Lower
If either myToLower s1 or myToLower s2 returns Nothing, then doSomething will return Nothing. There is no ambiguity, no chance for an unhandled exception, and no crashing at runtime. Haskell exceptions themselves, those thrown by the function throw, must be caught by catch, which has to execute in the IO monad. Without the IO monad, you can't catch exceptions. In pure functions, you can always represent the concept of failure with another data type without having to resort to throw, so there is no need to over-complicate code with it.
Alternative, you could have even written myToLower monadically as
import Control.Monad
-- Other code
myToLower :: String -> Maybe String
myToLower plaintext = do
guard $ not $ hasNonAlpha plaintext
return $ map toLower plaintext
The guard from Control.Monad acts as a sort of filter for MonadPlus instances. Since Maybe is an instance of MonadPlus (as are lists), this gives us very simple code.
Or, if you want to pass around an error message:
type MyError = String
myToLower :: String -> Either MyError String
myToLower plaintext = if hasNonAlpha plaintext
then Left $ "The string " ++ plaintext ++ " has non-alpha character(s)"
else Right $ map toLower plaintext
Then you can change the type of doSomething to match:
doSomething :: String -> String -> Either MyError String
doSomething s1 s2 = do
s1Lower <- myToLower s1
s2Lower <- myToLower s2
return $ s1Lower ++ s2Lower
If you notice, the monadic syntax lets us change the type signature of our function without even having to change the code! Play around with this implementation to get a feel for how it works.
Learning about exceptions is useful, and they are great for handling exceptional circumstances.
The best place to read about exceptions is Simon Marlow's paper, An Extensible Dynamically-Typed Heirarchy of Exceptions. His book, Parallel Concurrent Programming in Haskell is another good resource on their use.
The following are a few comments on your question.
error on line 61
handlerNonAlpha :: NonNumericException -> IO()
handlerNonAlpha ex =
putStrLn "Caught Exception: " ++ (show ex) ++ ...
Function arguments are consumed eagerly in haskell. You'll have to modify this line as follows to perform string concatenation before calling putStrLn:
putStrLn $ "Caught Exception: " ++ (show ex) ++ ...
comment on nonAlpha
Exceptions can only be caught from an IO computation, and it's best to avoid throwing them from pure functions. Besides this, the problem with nonAlpha is that it claims to return a Bool, but actually returns either True or throws an exception. Why not just return False?
nonAlpha :: String -> Bool
nonAlpha str =
let nonalphas = [x | x <- str, (ord x) < 65 || (90 < (ord x) && (ord x) < 97) || 123 < (ord x)]
in if (length nonalphas) == 0
then True
else False
Pull your exception throwing code out of nonAlpha like so. The name of this function and its lack of return value indicate that it might throw an exception:
trapInvalid :: String -> IO ()
trapInvalid str = unless (nonAlpha str) $ throw NonNumException

How to throw an exception and exit the program in Haskell?

I have a question: how do I throw an exception and exit the program? I have writen down a simple example:
-- main.hs
import Test
main = do
Test.foo ""
putStrLn "make some other things"
Here is the module:
moldule Test where
foo :: String -> IO ()
foo x = do
if null x
then THROW EXCEPTION AND EXIT MAIN else putStrLn "okay"
I want to start this and throw a exception and exit the program, but how?
Well, you could try
foo :: String -> IO ()
foo x = do
if null x
then error "Oops!" else putStrLn "okay"
Or, if you intend to catch the error eventually, then
import Control.Exception
data MyException = ThisException | ThatException
deriving (Show, Typeable)
instance Exception MyException
...
foo :: String -> IO ()
foo x = do
if null x
then throw ThisException else putStrLn "okay"
There are often more haskelly mechanisms that you could use, such as returning values packed in Maybe type or some other structure that describes the failure. Exceptions seem to fit better in cases where returning complicated types would complicate otherwise re-usable interfaces too much.