Hi I have a similar to the following haskell function
test :: Int -> Bool
test 1 = error "shouldnt have been 1"
test 2 = error "shouldnt have been 2"
test 11 = error "shouldnt have been 11"
test 77 = error "shouldnt have been 77"
test _ = True
I have a testing scheme to test bad inputs to make sure they return the correct error
tc1 = test 1
tc2 = test 2
tc3 = test 11
tc4 = test 77
allTests = [tc1, tc2, tc3, tc4]
But the problem is that when I run allTests in ghci, I only get the first error. I would like to have a list of all the errors
How can this be done or some way I can catch the errors?
You could try to use catch from Control.Exception, but that's still an awkward way to achieve the goal.
It'd be better to use a pure data type to capture errors, as they're easier to compose and collect. Normally, you'd use Either for that, but in this particular case, the success case would carry no information, so the type would be Either String (), which is isomorphic to Maybe String. Rewriting test to return Maybe String is trivial:
test :: Int -> Maybe String
test 1 = Just "shouldnt have been 1"
test 2 = Just "shouldnt have been 2"
test 11 = Just "shouldnt have been 11"
test 77 = Just "shouldnt have been 77"
test _ = Nothing
tc1 = test 1
tc2 = test 2
tc3 = test 11
tc4 = test 77
tc5 = test 5
I added a tc5 value in order to demonstrate what happens when a test succeeds.
You can evaluate all of those test cases, but if you want only the failure cases, you can use catMaybes from Data.Maybe:
allTests = catMaybes [tc1, tc2, tc3, tc4, tc5]
Here's the result of running allTests:
*Q46376632> allTests
["shouldnt have been 1",
"shouldnt have been 2",
"shouldnt have been 11",
"shouldnt have been 77"]
If you can't change the function you're testing, you can try something like the following, but it's hardly elegant:
tc1 = catch (print $ test 1) (\err -> print (err :: SomeException))
tc2 = catch (print $ test 2) (\err -> print (err :: SomeException))
tc3 = catch (print $ test 11) (\err -> print (err :: SomeException))
tc4 = catch (print $ test 77) (\err -> print (err :: SomeException))
tc5 = catch (print $ test 5) (\err -> print (err :: SomeException))
allTests = sequence_ [tc1, tc2, tc3, tc4, tc5]
When running it, you get output like this:
*Q46376632> allTests
shouldnt have been 1
CallStack (from HasCallStack):
error, called at 46376632.hs:14:10 in main:Q46376632
shouldnt have been 2
CallStack (from HasCallStack):
error, called at 46376632.hs:15:10 in main:Q46376632
shouldnt have been 11
CallStack (from HasCallStack):
error, called at 46376632.hs:16:11 in main:Q46376632
shouldnt have been 77
CallStack (from HasCallStack):
error, called at 46376632.hs:17:11 in main:Q46376632
True
At this point, you'd probably be better of using a proper testing framework.
Related
I'm trying to make the folowing function:
repcountIORIban :: IORef -> Int -> Int -> Int -> Int -> Lock -> IORef -> Lock -> Int -> Int -> IO ()
repcountIORIban count number lower modulus amountthreads lock done lock2 difference rest = do
if rest > number
then let extra = 1
else let extra = 0
if number + 1 < amountthreads
then
forkIO $ realcountIORIban(count lower (lower + difference + extra - 1) modulus lock done lock2)
repcountIORIban (count (number + 1) (lower + difference + extra) modulus amountthreads lock done lock2 difference rest)
else
forkIO $ realcountIORIban(count lower (lower + difference + extra - 1) modulus lock done lock2)
But I can't run the program from which this function is a part of. It gives me the error:
error: parse error on input `else'
|
113 | else let extra = 0
| ^^^^
I've got this error a lot of times withing my program but I don't know what I'm doing wrong.
This is incorrect, you can't let after then/else and expect those lets to define bindings which are visible below.
do if rest > number
then let extra = 1 -- wrong, needs a "do", or should be "let .. in .."
else let extra = 0
... -- In any case, extra is not visible here
Try this instead
do let extra = if rest > number
then 1
else 0
...
Further, you need then do if after that you need to perform two or more actions.
if number + 1 < amountthreads
then do
something
somethingElse
else -- use do here if you have two or more actions
...
I am new to haskell
I have this program:
loop height weight=do
line<-getLine
if line=="1" then
do
height<-getLine
loop height weight
else if line=="2" then
do
weight<-getLine
loop height weight
else if line=="3" then
do
putStrLn (height)
else
do
putStrLn "error"
main :: IO ()
main = do
loop "" ""
It works fine,now I change it as this:
data A=A {height::String,weight::String}
loop::A->IO ()
loop z=do
line<-getLine
if line=="1" then
do
height<-getLine
let z.height=height
loop z
else if line=="2" then
do
weight<-getLine
let z.weight=weight
loop z
else if line=="3" then
do
putStrLn ((height z)++(weight z))
else
do
putStrLn "error"
main :: IO ()
main = do
let z=A "" ""
loop z
this program is wrong
I know in haskell and other function program there is no assignment,so let z.height=height is wrong,but I don't know how to write it right.I need some help,thanks!
You can use the record update notation:
if line=="1" then
do
height'<-getLine
loop z{height = height'}
Basically, z{height = height'} is a new record value, having the same fields as z except for the updated one. In this case, it is equivalent to A height' (weight z).
I am writing some simple programs about reading and writing files in SML, and I am thinking to track if a file is successfully opened / overflow happens, etc. If any exceptions are raised during complilation, I want the function to return false else true.
Is such implementation doable? If so, how? If not, any alternative solutions?
I am not sure if I am doing it correctly:
fun getN(file) =
let
val input = TextIO.openIn file
fun num(n) =
case n of
NONE => []
| SOME(str) => str_to_num(str) # num(TextIO.inputLine input)
in
if OS.FileSys.access(file, []) then
num(TextIO.inputLine input) before TextIO.closeIn input
else []
//OR
num(TextIO.inputLine input) before TextIO.closeIn input
handle Io => []
end;
However, neither of these solutions does not return [] when the directory of the file does not exist. Why?
Yes, that is doable:
fun wasExceptionRaised f x = (f x; false) handle e => true
This will execute f x, discard the result and return false, unless an exception was raised, in which case that exception, e, is handled, discarded and true is returned. Although you probably want to handle specific exceptions and not others, for example when testing:
val test_should_not_find_file =
(TextIO.openIn "non-existing-file"; false)
handle Io { cause = SysErr ("No such file or directory", _), ... } => true
| _ => false
If you're just logging if an exception was thrown, you may do something similar:
structure YourLogger =
struct
fun logException e =
let val time = Date.toString (Date.fromTimeLocal (Time.now ()))
val msg = "On " ^ time ^ " an error occurred: "
^ General.exnName e ^ ".\n"
^ General.exnMessage e
in appendFile "myLog.txt" msg end
fun logged f x = f x handle e => (logException e; raise e)
end
Now, instead of calling f x, you may call logged f x to get the same result, but where any exceptions are logged.
I am trying to use Spin Model Checker to modelcheck a Game between two objects (A and B). The objects move on a board, and each location is defined by its (x,y) coordinates. The two objects are supposed to not collide. I have three processes: init, A Model, B Model. I am model checking an ltl property: (liveness property to check if the two objects ever occupy same location)
ltl prop1 { [] (!(x_a == x_b) && !(y_a == y_b)) }
The error trail that I get is:
init -> A Model -> B Model -> init
However, I should not get an error trail (counterexample) based on the data that is shown: x_a=2, x_b=1, y_a=1, y_b=1.
Also the first init does go through all the lines of init process, but the second one only shows to the last line of it.
Also my A Model and B Model only consist of guards and actions in a 'do' block as shown below. However they are more complex and have if blocks on the right of '->'
active proctype AModel(){
do
:: someValue == 1 -> go North
:: someValue == 2 -> go South
:: someValue == 3 -> go East
:: someValue == 4 -> go West
:: else -> skip;
od
}
Do I need to put anything in an atomic block? The reason I am asking is that the line that the error trail is showing does not even go into the 'do' block, and it is just the first line of the two models.
EDIT:
The LTL property was wrong. I changed that to:
ltl prop1 { [] (!((x_a == x_b) && (y_a == y_b))) }
However, I am still getting the exact same error trail.
Your LTL property is wrongly implemented. Essentially, the counter example that SPIN found is a true counter example for the LTL as stated.
[] ( !(x_a == x_b) && !(y_z == y_b) ) =>
[] ( !(2 == 1) && !(1 == 1) ) =>
[] ( !0 && !1) =>
[] ( 1 && 0) =>
[] 0 =>
false
The LTL should be:
always not (same location) =>
[] (! ((x_a == x_b) && (y_a == y_b))) =>
[] (! ((2 == 1) && (1 == 1))) =>
[] (! (0 && 1) =>
[] (! 0) =>
[] 1 =>
true
Regarding your init and tasks. When starting your tasks you want to be sure that initialization is complete before the tasks run. I'll use one of two approaches:
init { ... atomic { run taskA(); run taskB() } where tasks are spawned once all initialization is complete`
or
bool init_complete = false;
init { ...; init_complete = true }
proctype taskA () { /* init local stuff */ ...; init-complete -> /* begin real works */ ... }
Your LTL may be failing during the initialization.
And based on your problem, if you ever change x or y you'd better change both at once in an atomic{}.
Here's the SQLite3 Haskell bindings with the ability to create function: http://hackage.haskell.org/packages/archive/sqlite/0.5.1/doc/html/Database-SQLite.html
But I can't get to use this feature, I wrote the code like this:
increment a = a + 1
checkout = do
handle <- openConnection "test.db"
ok <- createFunction handle "woot" (IsFunctionHandler increment)
return $ execStatement handle "SELECT woot(5)";
But it isn't compile with "Not in scope: data constructor `IsFunctionHandler'" error
The correct code is:
module Test where
import Database.SQLite
import Int
increment :: Int64 -> Int64
increment a = a + 1
checkout :: IO (Either String [[Row Value]])
checkout = do
handle <- openConnection "test.db"
ok <- createFunction handle "woot" increment
execStatement handle "SELECT woot(5), woot(7), woot(128)"
Thanks to HaskellElephant
IsFunctionHandler is a class, not a data constructor. It has several instances so if increment is an instance of IsFunctionHandler, wich it in this case is, you should be able to write:
createFunction handle "woot" increment