awaitEval in Concurrent Haskell

Colin Runciman colin@cs.york.ac.uk
Mon, 17 Feb 2003 13:40:12 +0000


This is a multi-part message in MIME format.
--------------040603000002010004050603
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

A couple of hours ago, I wrote (in reponse to Claus Reinke's suggestion):

> Thanks for this further suggestion.  A solution along these lines 
> might be
> possible, but it would still be restricted ...

Actually a mild variant of Claus's proposal seems to work out
quite well.  Another way to avoid the problems with types is
to use a multi-parameter type class.  Little example attached.

So, thanks again Claus!

Regards
Colin R


--------------040603000002010004050603
Content-Type: text/plain;
 name="test3.hs"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="test3.hs"

-- A mini-experiment in concurrent data-driven assertions.
-- Colin Runciman after Claus Reinke after Andy Gill after ...
-- February 2003

import Control.Concurrent
import Char(isLower)
import System.IO.Unsafe(unsafePerformIO)

-- Each type a over which assertions are to be made is
-- encoded using a metatype b.

class Assert a b | a -> b, b -> a where
  assertW :: MVar b -> a -> a
  assertR :: MVar b -> a
  
assert :: Assert a b => String -> (a->Bool) -> a -> a
assert s p x = unsafePerformIO $ do
                 mv <- newEmptyMVar
		 forkIO $ check s p (assertR mv)
		 return $ assertW mv x
		 
check :: String -> (a -> Bool) -> a -> IO ()
check s p x | p x       = return ()
            | otherwise = putStrLn $ "assertion failure: " ++ s

-- We can use assertions over characters, encoded as themselves.

instance Assert Char Char where
  assertW mv c = unsafePerformIO $ do
                   putMVar mv c
		   return c
  assertR mv   = unsafePerformIO $ do
                   c <- takeMVar mv
		   return c
		   
-- Here's the metatype encoding for lists; similar definitions
-- would be needed for other structured types.

data MetaList a = Nil
                | Cons (MVar a) (MVar (MetaList a))
		 
instance Assert a b => Assert [a] (MetaList b) where
  assertW mv []     = unsafePerformIO $ do
                        putMVar mv Nil
		        return []
  assertW mv (x:xs) = unsafePerformIO $ do
                        mvx  <- newEmptyMVar
			mvxs <- newEmptyMVar
			putMVar mv (Cons mvx mvxs)
			return (assertW mvx x : assertW mvxs xs)
  assertR mv        = unsafePerformIO $ do
                        ml <- takeMVar mv
			return $ case ml of
			         Nil ->
				   []
			         (Cons mvx mvxs) ->
				   (assertR mvx : assertR mvxs)

-- Finally, a simple example application.

singleCaseWords :: String -> Bool
singleCaseWords  xs = all unmixed (words xs)

unmixed :: String -> Bool
unmixed "" = True
unmixed (c:cs) | isLower c = all isLower cs
               | otherwise = not (any isLower cs)
	       
main = do
  input <- getContents
  putStr (assert "single-case words" singleCaseWords input)
  
  
  

--------------040603000002010004050603--