Suppose I have a function that should calculate some value in one case and
throw an exception otherwise. I would like to use QuickCheck to ensure my
function behaves correctly, however is not obvious how to perform this sort
of check. Is it possible and if yes, how to check that exception of certain
type is thrown and it contains correct information about its cause?
Indeed ioProperty is the key to this sort of test. You will need to use it in combination with catch or try. Here I show the latter:
prop_exceptional :: Int -> Property
prop_exceptional n = ioProperty $ do
result <- try . evaluate $ myDangerousFunction n
return $ r === result
where r | n == 0 = Left MyException
| otherwise = Right 42
Quite obviously, myDangerousFunction should throw MyException whenever it gets 0 and return 42 otherwise. Note the useful function evaluate, which you need to use to evaluate pure function in IO context to catch exceptions produced there.
Related
I've read "Tackling the Awkward Squad" paper by SPJ and most of it was quite easy to follow however I didn't completely understand what exactly those two conditions above the separation line mean:
In paper it is stated that they are here to ensure that the second context (E2) is maximal, i.e. it includes all the active catches. However I do not completely understand what it means. Does it mean that an exception won't be thrown if there is a catch inside of a second thread? But why is bind also there then?
Intuitively, it is used to "insert" the exception ioError e in the right place, in a deterministic way.
Consider M = catch (threadDelay 1000000) someHandler. We have both:
M = Ea[M]
where Ea[x] = x
M = Eb[M']
where Eb[x] = catch x someHandler
M' = threadDelay 1000000
without the side condition, we would have two distinct operational steps, making the semantics non-deterministic:
{throwTo t e}s | {M}t ==> {return ()}s | {Ea[ioError e]}t
= {return ()}s | {ioError e}t
{throwTo t e}s | {M}t ==> {return ()}s | {Eb[ioError e]}t
= {return ()}s | {catch (ioError e) someHandler}t
In the former case, the error is not caught, in the latter it is. The side condition ensures only the latter is a valid step.
Bind is there as well to avoid replacing everything in:
M = catch (threadDelay 1000000) someHandler >>= something
Here, if you only require "M not a catch", you could again choose M = Ea[M] and replace all the code. The side condition instead forces you to choose
Ec[x] = catch x someHandler >>= something
and insert the ioError e in the correct place inside the catch.
I'm trying to practice Haskell returns and datatypes. I'm trying to pass the following information into the program:
worm = 1:2:3:worm
eel = [1,2,3,1,2,3,1,2,3]
snake = 3:2:1:snake
whale = [1..100]
And i want to create a function that has a switch function to get the data and match it to its definition. For example, in Python:
def compare(str): #for one case and using string to clarify
if str == "1:2:3:worm":
return "worm"
I know the datatypes are lists but causes a lot of confusion. My code is giving me an error of Could not deduce (Num Char) Arising from use of worm
My code:
which :: [a] -> String
which x | x == [1,2,3,1,2,3,1,2,3] = "worm" | x == 3:2:1:snake = "snake" | otherwise = "F"
Is there another approach i'm missing? and why is my function giving me that error?
Two problems:
You can't have a function that returns a list of numbers sometimes and a string other times. That's literally the entire point of a strongly typed language. If you want something like that, you need to use a sum type.
You can't compare infinite lists. You can try, but your program will never finish.
I have a list of Strings, errors. I do some checks and if any fail, I append a message to errors. Something like this:
let errors = []
let errors' = errors ++ if (check1 fails) then ["check1 failed"] else []
let errors'' = errors' ++ if (check2 fails) then ["check2 failed"] else []
Surely there is a more idiomatic way to accumulate changes to errors without making a new variable every time. Do I need to break out Data.IORef for mutable variables? Seems like overkill.
If I simply remove the apostrophes, the compiler returns an error because it gets caught in an infinite loop.
You could group the conditions and messages together
checksTodo = [(check1 fails, "check1 failed"), (check2 fails, "check2 failed")]
errors = map snd (filter fst checksTodo)
If you are comfortable using the list comprehension syntax, you could instead write it in a more readable fashion:
errors = [ msg | (cond, msg) <- checksTodo, cond ]
If I simply remove the apostrophes, the compiler returns an error because it gets caught in an infinite loop.
This is happening because let bindings in Haskell (unlike most languages) are recursive by default. Which means that if you say
let errors = errors ++ if (check1 fails) then ["check1 failed"] else []
the compiler will treat it as a recursive definition. When you try to evaluate errors at runtime, you go into an infinite loop as you need errors to compute errors.
Another alternative:
let errors =
[ "check1 failed" | check1 fails ] ++
[ "check2 failed" | check2 fails ] ++
...
What theindigamer said, plus, the idiomatic way to do error checking is usually having your checker return an Either: if something goes wrong, produce a Left with the error message, otherwise a Right with the result.
Since, in this case, your checks aren't producing an actual result, you can make the result the unit type (); thus, you can convert your checks to generate Either like this:
check1Either = if check1 fails then Left "check1 failed" else Right ()
And then, just run the checks and filter the elements with a Left using the lefts function in Data.Either:
import Data.Either
errors = lefts [check1Either, check2Either]
(You might ask, if there isn't going to be a result to fill Right with, why not use Maybe? You can, and filter errors with catMaybes from Data.Maybe; it's just that Nothing is usually interpreted to mean that the computation failed, and Just usually means success - the opposite of what happens here - whereas, idiomatically speaking Left is usually interpreted as an error)
With GHC version 8.0.2 the following program:
import Debug.Trace
f=trace("f was called")$(+1)
main = do
print $ f 1
print $ f 2
outputs:
f was called
2
3
Is it the expected behaviour? If yes, why? I expected the string f was called to be printed twice, one before 2 and one before 3.
Same result on TIO: Try it online!
EDIT
But this program:
import Debug.Trace
f n=trace("f was called:"++show n)$n+1
main = do
print $ f 1
print $ f 2
outputs:
f was called:1
2
f was called:2
3
Try it online!
I suspect those behaviours have something to do with laziness, but my questions remain: is this the expected behaviour and, if yes, why?
Hackage asserts this:
The trace function outputs the trace message given as its first
argument, before returning the second argument as its result.
I don't see it in the first example.
EDIT 2 Third example based on #amalloy comments:
import Debug.Trace
f n=trace "f was called"$n+1
main = do
print $ f 1
print $ f 2
outputs:
f was called
2
f was called
3
Your trace prints when defining f, not when calling it. If you want the trace to happen as part of the call, you should make sure it is not evaluated until a parameter is received:
f x = trace "f was called" $ x + 1
Also, when I run your TIO I don't see the trace appearing at all. trace is not really a reliable way to print things, because it cheats the IO model that the language is built on. The most subtle changes in evaluation order can disturb it. Of course for debugging you can use it, but as even this simple example demonstrates it is not guaranteed to help much.
In your edit, you quote the documentation of trace:
The trace function outputs the trace message given as its first
argument, before returning the second argument as its result.
And indeed this is exactly what happens in your program! When defining f,
trace "f was called" $ (+ 1)
needs to be evaluated. First, "f was called" is printed. Then, trace evaluates to, and returns, (+ 1). This is the final value of the trace expression, and therefore (+ 1) is what f is defined as. The trace has vanished, see?
It is indeed a result of laziness.
Laziness means that merely defining a value doesn't mean it will be evaluated; that will only happen if it's needed for something. If it's not needed, the code that would actually produce it doesn't "do anything". If a particular value is needed the code is run, but only the first time it would be needed; if there are other references to the same value and it is used again, those uses will just directly use the value that was produced the first time.
You have to remember that functions are values in every sense of the term; everything that applies to ordinary values also applies to functions. So your definition of f is simply writing an expression for a value, the expression's evaluation will be deferred until the value of f is actually needed, and as it's needed twice the value (function) the expression computes will be saved and reused the second time.
Lets look at it in more detail:
f=trace("f was called")$(+1)
You're defining a value f with a simple equation (not using any syntactic sugar for writing arguments on the left hand side of the equation, or providing cases via multiple equations). So we can simply take the right hand side as a single expression that defines the value f. Just defining it does nothing, it sits there until you call:
print $ f 1
Now print needs its argument evaluated, so this is forcing the expression f 1. But we can't apply f to 1 without first forcing f. So we need to figure out what function the expression trace "f was called" $ (+1) evaluates to. So trace is actually called, does its unsafe IO printing and f was called appears at the terminal, and then trace returns its second argument: (+1).
So now we know what function f is: (+1). f will now be a direct reference to that function, with no need to evaluate the original code trace("f was called")$(+1) if f is called again. Which is why the second print does nothing.
This case is quite different, even though it might look similar:
f n=trace("f was called:"++show n)$n+1
Here we are using the syntactic sugar for defining functions by writing arguments on the left hand side. Let's desugar that to lambda notation to see more clearly what the actual value being bound to f is:
f = \n -> trace ("f was called:" ++ show n) $ n + 1
Here we've written a function value directly, rather than an expression that can be evaluated to result in a function. So when f needs to be evaluated before it can be called on 1, the value of f is that whole function; the trace call is inside the function instead of being the thing that is called to result in a function. So trace isn't called as part of evaluating f, it's called as part of evaluating the application f 1. If you saved the result of that (say by doing let x = f 1) and then printed it multiple times, you'd only see the one trace. But the when we come to evaluate f 2, the trace call is still there inside the function that is the value of f, so when f is called again so is trace.
I'm currently working my way through Learn You a Haskell for Great Good, and I'm trying to modify one of the code snippets in chapter nine, "Input and Output" to handle errors correctly:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else
let (Just action) = result
action args
where
dispatch :: [(String, [String] -> IO ())]
is an association list
and
errorExit :: IO ()
is some function that prints an error message.
Compiling this with GHC gives the error message
todo.hs:20:13: parse error in let binding: missing required 'in'
which (to my understanding), seems to be saying that the "let" here doesn't realise it's in a "do" block.
Adding "do" on lines five and seven (after "then" and "else" respectively), changes the error message to
todo.hs:20:13:
The last statement in a 'do' block must be an expression
let (Just action) = result
todo.hs:21:5: Not in scope: `action'.
and now, whilst I agree with the first error message, I also have that one of my variables has jumped out of scope? I've double checked my alignment, and nothing seems to be out of place.
What is the appropriate way to assign a varaible within an if clause that is within a do block?
My suggestion is to not use if in the first place, use case. By using case you get to test the value and bind the result to a variable all in one go. Like this:
main = do
(command:args) <- getArgs
case lookup command dispatch of
Nothing -> errorExit
Just action -> action args
For a more in-depth discussion on why we should prefer case over if see boolean blindness.
#svenningsson suggested the right fix. The reason your original fails is because let clauses can only appear at the top level of a do block - they're simple syntactic sugar that doesn't look into inner expressions:
do let x = 1
y
desugars to the let expression
let x = 1 in y
Alas, in a do block, an expression clause like if ... then ... else ... has no way to declare variables in the rest of the do block at all.
There are at least two possible ways to get around this.
Absorb the remainder of the do block into the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else do
let (Just action) = result
action args
(This is essentially the method #svenningsson uses in his better case version too.)
This can however get a bit awkward if the remainder of the do expression needs to be duplicated into more than one branch.
("Secret" trick: GHC (unlike standard Haskell) doesn't actually require a final, inner do block to be indented more than the outer one, which can help if the amount of indentation starts getting annoying.)
Pull the variable declaration outside the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
action <- if result == Nothing
then
errorExit
else do
let (Just action') = result
return action'
action args
Here that requires making up a new variable name, since the pattern in the let clause isn't just a simple variable.
Finally, action was always out of scope in the last line of your code, but GHC works in several stages, and if it aborts in the parsing stage, it won't check for scope errors. (For some reason it does the The last statement in a 'do' block must be an expression check at a later stage than parsing.)
Addendum: After I understood what #Sibi meant, I see that result == Nothing isn't going to work, so you cannot use if ... then ... else ... with that even with the above workarounds.
You are getting an error because you are trying to compare values of function type. When you perform the check if result == Nothing, it tries to check the equality of Nothing with the value of result which is a type of Maybe ([String] -> IO ()).
So, if you want it to properly typecheck, you have to define Eq instances for -> and that wouldn't make any sense as you are trying to compare two functions for equality.
You can also use fmap to write your code:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
print $ fmap (const args) result