In SML, how to assert that a particular exception is thrown? - exception

Without taking the effort to actually clone JUnit or something, I'm throwing together a few utility functions to help test some SML code. I do know about QCheck, but it can't do this one thing either and isn't what I want generally. (But if you know of another automated-testing framework for SML, please speak up.)
I'd like to be able to assert that some function will throw an exception, e.g., given a function
fun broken x = raise Fail
I'd like to be able to write something like
throws ("ERROR: function is not broken enough!", fn () => broken 1, Fail)
and have it throw an error if the given function does not raise the expected exception.
I tried to write a throws function with type (string * exn * (unit -> unit)) -> unit like so:
fun throws (msg, e, func) = func ()
handle e' => if e = e'
then ()
else raise ERROR (SOME msg)
But this generates a bunch of compile-time errors, apparently because ML
does not define equality over exceptions:
sexp-tests.sml:54.31-57.49 Error: types of rules don't agree [equality type required]
earlier rule(s): ''Z -> unit
this rule: exn -> 'Y
in rule:
exn => raise exn
sexp-tests.sml:54.31-57.49 Error: handler domain is not exn [equality type required]
handler domain: ''Z
in expression:
func ()
handle
e' => if e = e' then () else raise (ERROR <exp>)
| exn => raise exn
As a workaround, I suspect I could just reuse an existing assert function I have:
assert ((broken 1; false) handle Fail => true | _ => false)
But it's a bit more thinking and typing.
So, is there any way to write that throws function in SML?

This following function should work:
exception ERROR of string option;
fun throwError msg = raise ERROR (SOME msg);
fun throws (msg, func, e) =
(func (); throwError msg) handle e' =>
if exnName e = exnName e'
then ()
else raise throwError msg
This uses the function exnName, which gets the name of the exception as a string, and uses that for comparison instead.
More importantly, it also handles the case where no exception is thrown at all, and gives an error on that, too.
Alternatively, if you simply need a boolean value, indicating whether the exception was thrown or not, you can use:
fun bthrows (func, e) = (func (); false) handle e' => exnName e = exnName e'
Note that, for the case of Fail, you'll actually have to create an instance of a Fail-exception, for instance like so:
throws ("ERROR: Oh no!", fn () => test 5, Fail "")
Alternatively, you could take the name of the exception, for a cleaner general case:
fun throws (msg, func, e) =
(func (); throwError msg) handle e' =>
if e = exnName e'
then ()
else raise throwError msg
fun bthrows (func, e) = (func (); false) handle e' => e = exnName e'
And then use it like this:
throws ("ERROR: Oh no!", fn () => test 5, "Fail")

Related

throw exception in async

I have the following code:
member public this.GetData(uri: string) = async {
let! res = Async.AwaitTask(httpClient.GetAsync uri)
return res
}
When the property res.IsSuccessStatusCode is false I would like to throw an exception, how can I achieve this. The following code won't compile:
member public this.GetData(uri: string) = async {
let! res = Async.AwaitTask(httpClient.GetAsync uri)
match res.IsSuccessStatusCode with
| true -> return res
| false -> raise new Exception("")
}
You certainly need to wrap new Exception(...) in brackets, but that is not sufficient in this case - both branches of the match statement need to return a value, so you also need to insert return:
async {
let! res = Async.AwaitTask(httpClient.GetAsync uri)
match res.IsSuccessStatusCode with
| true -> return res
| false -> return raise (new Exception(""))
}
This is actually easier to write using an if computation which can contain body that returns unit (and throws an exception if the operation did not succeed) - and so you do not need return in that case:
async {
let! res = Async.AwaitTask(httpClient.GetAsync uri)
if not res.IsSuccessStatusCode then
raise (new Exception(""))
return res
}
So the first part is that you need to wrap the new Exception() with brackets to make sure that F# interprets the code correctly.
raise (new Exception(""))
or you can use either of the pipe operators
raise <| new Exception("")
new Exception |> raise
or you can change the type and use failwith
failwith "some message"
Secondly, you need to return from both branches, so prefix raise with return

Async Exception Handling in F#

I am trying to write non-blocking code in F#. I need to download a webpage, but sometime that webpage doesn't exist and an exception is thrown (404 Not Found) by AsyncDownloadString. I tried the code below but it doesn't compile.
How could I handle exception from AsyncDownloadString?
let downloadPage(url: System.Uri) = async {
try
use webClient = new System.Net.WebClient()
return! webClient.AsyncDownloadString(url)
with error -> "Error"
}
How am I suppose to handle exception here? If an error is thrown, I simply want to return an empty string or a string with a message in it.
Just add the return keyword when you return your error string:
let downloadPage(url: System.Uri) = async {
try
use webClient = new System.Net.WebClient()
return! webClient.AsyncDownloadString(url)
with error -> return "Error"
}
IMO a better approach would be to use Async.Catch instead of returning an error string:
let downloadPageImpl (url: System.Uri) = async {
use webClient = new System.Net.WebClient()
return! webClient.AsyncDownloadString(url)
}
let downloadPage url =
Async.Catch (downloadPageImpl url)

Types and functions

Consider the following:
type T () =
member x.y = 4
let a =
let fn () (k: T) = ()
fn ()
let b =
let fn () (k: System.IO.Directory) = ()
fn ()
a fails while b is ok. The error message is:
The value 'a' has been inferred to have generic type val a : ('_a -> unit) when '_a :> T Either make the arguments to 'a' explicit or, if you do not intend for it to be generic, add a type annotation
Why and how to fix that?
The error message itself tells you exactly what you need to do - add a type annotation:
let a : T -> unit =
let fn () (k: T) = ()
fn ()
The reason that you see the error in the first place is that the compiler tries to generalize the definition of a (see this part of the spec), which results in the odd signature that you see in the error message.
The reason that you don't need to do this for b is that System.IO.Directory is sealed, so there is no need to generalize.
You are facing a value restriction, because a looks like a constant but it returns a function.
Have a look at this question:
Understanding F# Value Restriction Errors
One easy way to solve it is adding a variable to the definition of a.
let a x =
let fn () (k: T) = ()
fn () x
I don't know why with some types it works, which is the case of b
If T where a record instead of a class, it would work. But for some reason, you have to spell it out for the compiler if T is a class,
type T () =
member x.y = 4
let a<'U when 'U :> T> =
let fn () (k: 'U) = ()
fn ()
let test0 = a<T> (T()) // You can be explicit about T,
let test1 = a (T()) // but you don't have to be.
edit: So I played a bit more with this, and weirdly, the compiler seems to be content with just any type restriction:
type T () =
member x.y = 4
type S () =
member x.z = 4.5
let a<'U when 'U :> S> =
let fn () (k: T) = ()
fn ()
let test = a (T()) // Is OK
let test = a<T> (T()) // Error: The type 'T' is not compatible with the type 'S'
The type S has nothing to do with anything in the code above, still the compiler is happy to just have a restriction of any kind.

Haskell: Dealing With Types And Exceptions

I'd like to know the "Haskell way" to catch and handle exceptions. As shown below, I understand the basic syntax, but I'm not sure how to deal with the type system in this situation.
The below code attempts to return the value of the requested environment variable. Obviously if that variable isn't there I want to catch the exception and return Nothing.
getEnvVar x = do {
var <- getEnv x;
Just var;
} `catch` \ex -> do {
Nothing
}
Here is the error:
Couldn't match expected type `IO a'
against inferred type `Maybe String'
In the expression: Just var
In the first argument of `catch', namely
`do { var <- getEnv x;
Just var }'
In the expression:
do { var <- getEnv x;
Just var }
`catch`
\ ex -> do { Nothing }
I could return string values:
getEnvVar x = do {
var <- getEnv x;
return var;
} `catch` \ex -> do {
""
}
however, this doesn't feel like the Haskell way. What is the Haskell way?
Edit: Updated code to properly reflect description.
You cannot strip away the IO and return Maybe String within a do-block. You need to return an IO (Maybe String).
getEnvVar x = do {
var <- getEnv x;
return (Just var);
} `catch` \ex -> do {
return Nothing
}
Why not use
import qualified System.IO.Error as E
getEnvVar :: String -> IO (Either IOError String)
getEnvVar = E.try . getEnv
Instead of Nothing and Just var, you get Left error and Right var.
Once you get that anything involving getEnv is going to involve returning a result in the IO monad, then there is nothing wrong with your basic approach. And while you could use System.IO.Error (and I would), it is just as valid, and instructive, to write it the way you did. However, you did use a bit more punctuation than idomatic Haskell would use:
getEnvVar x = (Just `fmap` getEnv x) `catch` const (return Nothing)
or
getEnvVar x = getEnv x `catch` const (return "")
You could also try
import System.Environment
getEnvVar :: String -> IO (Maybe String)
getEnvVar x = getEnvironment >>= return . lookup x
or a bit longer, but maybe easier to follow:
getEnvVar x = do
fullEnvironment <- getEnvironment
return (lookup x fullEnvironment)
if you don't mind going through the whole environment the whole time.

F#: Custom exceptions. Is there a better way to overload the exception type?

I have a simple custom exception defined like like the following but I don't like having to use the Throw function and I really don't like having both Throw and a Throw2 functions. Is there a more elegant way of doing this? Is there a way of throwing MyError or Error directly without the intermediate function?
#light
module Utilities.MyException
type MyError(code : int, msg : string) =
member e.Msg = msg
member e.Code = code
new (msg : string) = MyError(0, msg)
exception Error of MyError
let public Throw (msg : string) =
let err = new MyError(msg)
raise (Error err)
let public Throw2 (code : int) (msg : string) =
let err = new MyError(code, msg)
raise (Error err)
I'm using it like the following but I'd like to use one of the variants that didn't work
Throw(System.String.Format("Could not parse boolean value '{0}'", key))
//The string isn't of the correct type for Error
//raise(Error(System.String.Format("Could not parse boolean value '{0}'", key)))
//MyError isn't compatible with System.Exception
//raise(MyError(System.String.Format("Could not parse boolean value '{0}'", key)))
Just ignore exception construct and define the exception class - that is, one deriving from System.Exception - directly, as in C#:
type MyError(code : int, msg : string) =
inherit Exception(msg)
member e.Code = code
new (msg : string) = MyError(0, msg)
raise(MyError("Foo"))
raise(MyError("Foo", 1))
Note that I removed Msg member, because Exception has an equivalent Message property already.
I am unclear exactly what you are after, but how does this work for you?
exception Error of int * string
let ErrorC(s) = Error(0,s)
let F() =
try
let key = true
raise <| Error(42, System.String.Format("Could not parse '{0}'", key))
raise <| ErrorC(System.String.Format("Could not parse '{0}'", key))
with Error(code, msg) ->
printfn "%d: %s" code msg
How about redefining MyError as a record and using the record syntax to record the error, e.g.:-
type MyError =
{ Msg: string;
Code: int }
exception Error of MyError
raise <| Error { Msg = ( sprintf "Could not parse boolean value '%b'" key );
Code = code }