
Hi, As a learning exercise, I'm trying to make a Haskell module (my first) that implements a TAP library (http://testanything.org/). The library basically provides some functions to perform unit tests and keeps track of some state. It also performs quite a bit of IO as it goes a long. As a first step I'm loosely basing my code on a Java implementation. You can find the code here: http://svn.solucorp.qc.ca/repos/solucorp/JTap/trunk/JTap.java. I've setup my TapState data structure and a monad transformer to be able to keep state and do IO within the same functions: data TapState = TapState { planSet :: Bool, noPlan :: Bool, skipAll :: Bool, testDied :: Bool, expectedTests :: Int, executedTests :: Int, failedTests :: Int } deriving (Show) type TAP a = StateT TapState IO a In the Java version there is a function called cleanup that is called after all the tests are performed to determine the return code and print some diagnostics: private int cleanup(){ int rc = 0 ; if (! plan_set){ diag("Looks like your test died before it could output anything.") ; return rc ; } if (test_died){ diag("Looks like your test died just after " + executed_tests + ".") ; return rc ; } if ((! skip_all)&&(no_plan)){ print_plan(executed_tests) ; } if ((! no_plan)&&(expected_tests < executed_tests)) { diag("Looks like you planned " + expected_tests + " test" + (expected_tests > 1 ? "s" : "") + " but ran " + (executed_tests - expected_tests) + " extra.") ; rc = -1 ; } if ((! no_plan)&&(expected_tests > executed_tests)) { diag("Looks like you planned " + expected_tests + " test" + (expected_tests > 1 ? "s" : "") + " but only ran " + executed_tests + ".") ; } if (failed_tests > 0){ diag("Looks like you failed " + failed_tests + " test" + (failed_tests > 1 ? "s" : "") + " of " + executed_tests + ".") ; } return rc ; } I'm having problems implementing the equivalent of this function in haskell. Inside a do block, is there a way to terminate the function immediately and return a result ("return" in the imperative sense, not the Haskell sense)? If not, must one really use deeply nested if/then/else statements to treat these special cases? All I could come up was this, which I find quite ugly: _cleanup :: Int -> TAP Int _cleanup rc = do ts <- get if (not $ planSet ts) then do diag "Looks like your test died before it could output anything." return rc else if (testDied ts) then do diag $ "Looks like your test died just after " ++ (show $ executedTests ts) return rc else ... Thanks a lot, Patrick Note: If it helps, you can find my Haskell code here: http://svn.solucorp.qc.ca/repos/solucorp/JTap/trunk/tap.hs -- ===================== Patrick LeBoutillier Rosemère, Québec, Canada