How to include a integer while throwing a failure exception in OCaml - exception

I have this function
let f = function
| 1 -> "a"
| 2 -> "b"
| _ -> failwith "Argument should be less than 3 and more than 0 but it was found to be x"
How do I set the value of x here equal to the function's input?

You can use the standard library function sprintf present in the Printf module.
| x -> failwith (Printf.sprintf "Argument should be ... but it was %d" x)
Although, I would recommend you to use invalid_arg instead of failwith since you are throwing the exception due to an invalid argument.
Check out this page of the OCaml documentation.

If you wish to handle that exception, parsing that int out of the error message might be annoying.
Defining your own exception is something you should learn eventually when learning OCaml because it gives you the flexibility to pass any information you need in the exception. Here's a simple example:
exception Out_of_range of {
range_start : int;
range_end : int;
received : int
}
Now, you can define your function as:
let f = function
| 1 -> "a"
| 2 -> "b"
| n -> raise (Out_of_range { range_start=1; range_end=2; received=n })
And when calling it, if you want to raise a Failure with a formatted string:
let n = read_int () in
try
f n
with
| Out_of_range {range_start=s; range_end=e; received=n} ->
failwith (Format.sprintf "Argument should be between %d and %d but it was found to be %d" s e n)

Related

OCaml 5.0.0~beta1: How to use an argument of Effect when their effect handler is not specified (Using Unhandled Exception)

I am using opam switch: 5.0.0~beta1
I was playing around with some simple functions (on utop):
type _ Effect.t += Foo : (unit -> unit) -> unit Effect.t
let a = try perform (Foo (fun () -> Printf.printf "Hello from Foo\n ")) with
| Unhandled (Foo f) -> f ();;
Output: Hello from Foo
val a: unit = ()
This works well.
But when we change the definition of Foo effect,
type _ Effect.t += Foo : ('a -> unit) -> unit Effect.t
let a = try perform (Foo (fun n -> Printf.printf "Hello from Foo\n ")) with
| Unhandled (Foo f) -> f 45;;
Error: This expression has type int but an expression was expected of type
$Foo_'a
Here I understand that it needs 'a as an input, but while calling the function, shouldnt it infer the type as int and replace 'a with int and execute the function accordingly? I want to call function f from Foo effect with different argument.
Here is the another example:
type _ Effect.t += Suspend : 'a -> unit Effect.t
let a = try perform (Suspend 32) with
| Unhandled (Suspend x) -> x;;
Error: This expression has type $Suspend_'a
but an expression was expected of type $Unhandled_'a
Here, I understand that return value of (try _ with) i.e. (unit) should be the type of $Unhandled_ 'a.
But I also want to know, what is $Unhandled_ 'a type? How is normal 'a is different from $Unhandled_ 'a? How to return $Unhandled_ 'a here? Why there is this special use of $Unhandled?
What will be its scope (In some examples where I was using following code,
type _ Effect.t += Foo : ('a -> unit) -> unit Effect.t
let p = try Lwt.return (some_function x) with
| Unhandled (Foo f) -> let (pr, res) = Lwt.task () in
let wkup v = (Lwt.wakeup res v; ()) in
f wkup;
pr
I also got error as :
This expression has type $Unhandled_'a Lwt.t
but an expression was expected of type 'a Lwt.t
The type constructor $Unhandled_'a would escape its scope
)?
Why there is
The type constructor $Unhandled_'a would escape its scope
error?
The effect part is a red-herring here, the root issue stems from the notion of existentially-quantified types in GADTs.
When you have a GADT which is defined as
type t = Foo : ('a -> unit) -> t
the type of Foo means that you can construct a t for any type 'a and any function of type 'a -> unit. For instance:
let l = [Foo ignore; Foo print_int]
However, once you have constructed such value, you can no longer knows which type was used to construct the value. If you have a value
let test (Foo f) = ...
you only know that there exists some type 'a such that f has type 'a -> unit. This why the type 'a is called an existentially type (aka a type such that we only know that it exists). The important things to remember is that you don't know which 'a. Consequently you cannot apply the function because applying to the wrong 'a would be a type error.
In other words, the function boxed in Foo f can never be called on any value.
This is slightly more subtle variant than the any type
type any = Any: 'a -> any
where the constructor Any takes a value of any type and put it in a black box from which it can never be extracted.
In a way existentially-quantified type variables in a GADT lives in their own world and they cannot escape it. But they can be still be useful if this inner world is large enough. For instance, I can bundle a value with a function that prints that value and then forget the type of this value with:
type showable = Showable: {x:'a; print:'a -> unit} -> showable
Here, I can call the function print on the value x because I know that whatever is 'a it is the same 'a for both x and print:
let show (Showable {x;print}) = print x
Thus I can store few showable values in a list
let l = [ Showable(0, print_int), Showable("zero", print_string)]
and print them later
let () = List.iter show l

F* Raising Exception in match body

I am trying to create a function in F* to determine the minimum element of a list, and I want to throw an exception if the list is empty. The code I have so far is below:
module MinList
exception EmptyList
val min_list: list int -> Exn int
let rec min_list l = match l with
| [] -> raise EmptyList
| single_el :: [] -> single_el
| hd :: tl -> min hd (min_list tl)
When I try to verify the file, however, I get the following error:
mcve.fst(7,10-7,15): (Error 72) Identifier not found: [raise]
1 error was reported (see above)
How can I fix this error?
This error comes up because raise is not a primitive in F* but needs to be imported from FStar.Exn (see ulib/FStar.Exn.fst), which exposes this function -- raise. Simply opening this module should be sufficient. There is one more minor issue in the code that I have also fixed below.
Here's the version of the code that goes through:
module MinList
open FStar.Exn
exception EmptyList
val min_list: list int -> Exn int (requires True) (ensures (fun _ -> True))
let rec min_list l = match l with
| [] -> raise EmptyList
| single_el :: [] -> single_el
| hd :: tl -> min hd (min_list tl)
Notice that I also have added requires and ensures clauses. This is because the Exn effect expects a these clauses to reason about the code in it. If your use case however, has exactly the above clauses (i.e., true and true), then you can use the convenient synonym for this, Ex (see ulib/FStar.Pervasives.fst). Thus, the following code is also valid and will behave exactly the same as the above code.
module MinList
open FStar.Exn
exception EmptyList
val min_list: list int -> Ex int
let rec min_list l = match l with
| [] -> raise EmptyList
| single_el :: [] -> single_el
| hd :: tl -> min hd (min_list tl)

Why can't I label the argument of a function that just raises an exception?

I am trying to write a function that just raises an exception. It works, but I cannot use it within another function when the argument is labeled.
Here is a simple example:
let raise_error ~m = failwith m
let test = function
| true -> raise_error "ok"
| false -> raise_error "ko"
There is a warning, and the function does not have the type I expected:
Warning 20: this argument will not be used by the function.
Warning 20: this argument will not be used by the function.
val test : bool -> m:string -> 'a = <fun>
This other function fails to compile:
let test2 = function
| true -> "ok"
| false -> raise_error "ko"
with the message:
Warning 20: this argument will not be used by the function.
Error: This expression has type m:string -> 'a
but an expression was expected of type string
I don't understand what's wrong, because it works if the argument is not labeled.
Is there a way to get around this?
You could label the arguments at the call sites:
let raise_error ~m = failwith m
let test = function
| true -> raise_error ~m:"ok"
| false -> raise_error ~m:"ko"
let test2 = function
| true -> "ok"
| false -> raise_error ~m:"ko"
A better solution is to rewrite raise_error to not use labelled arguments.
The issue is that raise_error as written has a type of m:string -> 'a, so you can pass it any number of non-labelled arguments and the resulting expression will still be a function of type m:string -> 'a. This is error prone and surprising, so you should avoid using labelled arguments with diverging functions.

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

FSharpTypeFunc.Specialize causing TypeLoadException

I'm getting the following run-time exception:
System.TypeLoadException was unhandled
Message=Method 'Specialize' on type [...] tried to implicitly override a method with weaker type parameter constraints.
This inner function appears to be the problem:
let getKey (r: IDictionary<_,_>) =
match r.TryGetValue(keyCol.Name) with
| true, k when not (isNull k) -> Some k
| _ -> None
The signature is IDictionary<string,'a> -> 'a option (requires 'a : null). The constraint is propagated from isNull.
Looking in ILSpy, getKey is compiled to a sub-type of FSharpTypeFunc that overrides Specialize<T>().
Is this a bug? I can work around it by boxing k in the call to isNull, which removes the constraint.
EDIT
Here's a full repro:
open System.Collections.Generic
let isNull = function null -> true | _ -> false
type KeyCol = { Name : string }
let test() =
seq {
let keyCol = { Name = "" }
let getKey (r: IDictionary<_,_>) =
match r.TryGetValue(keyCol.Name) with
| true, k when not (isNull k) -> Some k
| _ -> None
getKey (dict ["", box 1])
}
test() |> Seq.length |> printfn "%d"
This is a console app in Visual Studio 2008, targeting .NET 4.0. Strangely, the code works in FSI.
Here's PEVerify output for the assembly:
[token 0x02000004] Type load failed.
[IL]: Error: [D:\TEST\bin\Debug\TEST.exe : Test+test#10[a]::GenerateNext] [mdToken=0x6000012][offset 0x00000031] Unable to resolve token.
2 Error(s) Verifying D:\TEST\bin\Debug\TEST.exe
Sent it to fsbugs and received a reply that it's been fixed.