I think you're a rather stuck with the "temporary variables" (which they're not really), but it might be possible to hide some of the untidiness in an auxiliary monadic function.

Assuming this function is given:

assertBool :: String -> Bool -> IO ()

...

My first stab would be:

assertBool1 :: IO [a] -> IO [a] -> ([a] -> [a] -> Bool) -> IO ()
assertBool1 f1 f2 comp = do
        a1 <- f1
        a2 <- f2
        assertBool "fail" $ comp a1 a2

Then your main code could be:

assertBool1 (someFunc a) (someFunc b) (==)

...

So far so good, maybe? But what happens if the values you want to test are not lists? The assertBool1 could be generalized somewhat:

assertBool2 :: IO a -> IO b -> (a -> b -> Bool) -> IO ()
assertBool2 fa fb comp = do
        va <- fa
        vb <- fb
        assertBool "fail" $ comp va vb

(All that's really changed here is the type signature)

...

But what if you want a test that uses just one value, or three, or more? At this point I think you start having to use the liftM variants, but others may have better ideas. It may be that the lifting can be hidden in auxiliiarty function/operator definitions; e.g. see the Haskell library function Monad.ap for possible clues.

...

Anyway, here's some complete code, tested under Hugs:
[[
import Monad( unless )

assertBool :: String -> Bool -> IO ()
assertBool err bool = unless bool (error err)

someFunc :: String -> IO String
someFunc s = return s

assertBool1 :: IO [a] -> IO [a] -> ([a] -> [a] -> Bool) -> IO ()
assertBool1 f1 f2 comp = do
        a1 <- f1
        a2 <- f2
        assertBool "fail" $ comp a1 a2

test1 :: String -> String -> IO ()
test1 a b =
    do  { assertBool1 (someFunc a) (someFunc b) (==)
        ; putStrLn "test1 OK"
        }
-- test1 "a" "a" -> "test1 OK"
-- test1 "a" "b" -> "fail"

assertBool2 :: IO a -> IO b -> (a -> b -> Bool) -> IO ()
assertBool2 fa fb comp = do
        va <- fa
        vb <- fb
        assertBool "fail" $ comp va vb

test2 :: String -> String -> IO ()
test2 a b =
    do  { assertBool1 (someFunc a) (someFunc b) (==)
        ; putStrLn "test2 OK"
        }
-- test2 "a" "a" -> "test2 OK"
-- test2 "a" "b" -> "fail"
]]

#g
--

At 10:29 23/03/04 -0500, Sean E. Russell wrote:
Hello,

I posted this question to comp.lang.functional, and someone suggested that I
try this group instead.

I'm struggling with monads. Well, not monads themselves, but mixing them with
non-monadic functions.


Here's my base case:

        someFunc :: String -> IO [a]
        ...
                ax <- someFunc a
                bx <- someFunc b
                assertBool "fail" $ length ax == length bx

I don't like the assignments; the typing is redundant, if I have a lot of
asserts like this, and the "variables" are temporary.  What I'd much rather
have is:

...
assertBool "fail" $ (length $ someFunc a) == (length $ someFunc b)


which is more readable, to my eye.

The only solution which has been suggested that may work is liberal use of the
liftM variants, but this gets *really* tedious and obtuse.


Is there an elegant way to do what I want to do, or am I stuck with
procedural-style assignments and bunches of temp vars?

Thanks!

--
### SER
### Deutsch|Esperanto|Francaise|Linux|XML|Java|Ruby|Aikido
### http://www.germane-software.com/~ser  jabber.com:ser  ICQ:83578737
### GPG: http://www.germane-software.com/~ser/Security/ser_public.gpg
_______________________________________________
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell

------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

_______________________________________________
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell

Reply via email to