packages feed

KiCS-0.8.8: src/lib/Curry/Module/Meta.hs.include

[ForFunction "prim_isFree"
,ForFunction "headNormalFormIO"
,ForFunction "searchTree"
,ForFunction "gnfIO"
,ForFunction "ghnfIO"
,ForFunction "nfIO"
,ForFunction "hnfIO"
,ForType "OrRef" Nothing]

import System.Mem.Weak ( addFinalizer )
import Control.Concurrent
import System.IO.Unsafe ( unsafeInterleaveIO )
import Debug.Trace ( trace )
import Data.List

data C_OrRef = C_OrRef OrRef
  | C_OrRefFail Curry.RunTimeSystem.C_Exceptions
  | C_OrRefOr Curry.RunTimeSystem.OrRef (Curry.RunTimeSystem.Branches C_OrRef)

instance BaseCurry C_OrRef where
  nf f x state = f(x)(state)

  gnf f x state = f(x)(state)

  generator _ = error "free Variable of type OrRef"

  failed  = C_OrRefFail

  branching  = C_OrRefOr

  consKind (C_OrRefOr _ _) = Curry.RunTimeSystem.Branching
  consKind (C_OrRefFail _) = Curry.RunTimeSystem.Failed
  consKind _ = Curry.RunTimeSystem.Val

  exceptions (C_OrRefFail x) = x

  orRef (C_OrRefOr x _) = x

  branches (C_OrRefOr _ x) = x

instance Curry C_OrRef where
  strEq (C_OrRef x1) (C_OrRef y1) _ 
     = if x1 Prelude.== y1 then strEqSuccess else strEqFail "OrRef"
  strEq x0 _ _ = Curry.Module.Prelude.strEqFail(Curry.Module.Prelude.typeName(x0))

  eq (C_OrRef x1) (C_OrRef y1) _ = 
    if x1 Prelude.== y1 then C_True else C_False
  eq _ _ _ = C_False

  typeName _ = "OrRef"

  propagate _ o _ = o
  
  foldCurry _ c _ _ = c

  showQ d (C_OrRef x1) = showParen (d>10) (showString "Unsafe.OrRef" . showsPrec d x1)





instance Show C_OrRef where
  showsPrec d (C_OrRef x1) = showParen (d>10) (showString "OrRef" . showsPrec d x1)


instance Read C_OrRef where
  readsPrec d r = [ (C_OrRef ref,s) | (ref,s) <- readsPrec d r]


---------------------------------------------------------------------------------
-- test for free variable
---------------------------------------------------------------------------------

prim_isFree :: (Curry t0) => t0 -> Result (C_IO (C_Either t0 t0))
prim_isFree x _ = C_IO (\ _ -> case consKind x of
  Branching -> Prelude.return (IOVal (if isGenerator (orRef x) 
                              then C_Left x 
                              else C_Right x))
  _         -> Prelude.return (IOVal (C_Right x)))

---------------------------------------------------------------------------------
-- various normal forms in io monad
---------------------------------------------------------------------------------

-- yield head normal form with current state 
-- (including fetching and looking up variable bindings)
-- then apply continuation on it and make sure that you got a value
-- of type io before finally executing that action.

headNormalFormIO :: (Curry a,Curry b) => Prim (a -> Result (C_IO b)) -> a -> Result (C_IO b)
headNormalFormIO cont x _ = 
  C_IO (hnfCTC (\ x' st -> hnfCTC exec2 (apply cont x' st) st) x)

searchTree :: Curry a => a -> Result (C_SearchTree a)
searchTree = searchTr 

hnfIO  x _ = C_IO (hnfCTC  (\ x _ -> Prelude.return (IOVal x)) x)
nfIO   x _ = C_IO (nfCTC   (\ x _ -> Prelude.return (IOVal x)) x)
gnfIO  x _ = C_IO (ghnfCTC (\ x _ -> Prelude.return (IOVal x)) x)
ghnfIO x _ = C_IO (ghnfCTC (\ x _ -> Prelude.return (IOVal x)) x)

---------------------------------------------------------------------------------
-- rich search trees
---------------------------------------------------------------------------------

getRichSearchTree :: Curry a => a -> Result (C_IO (C_RichSearchTree a))
getRichSearchTree x _ = C_IO (\ state -> Prelude.return (IOVal (richSearchTr x state)))

richSearchTree :: Curry a => a -> Result (C_RichSearchTree a)
richSearchTree = richSearchTr 

--inject :: Curry a => C_Context -> a -> C_RichSearchTree a
--inject (Context c) = richSearchTr c
 
richSearchTr :: Curry a => a -> Result (C_RichSearchTree a)
richSearchTr x state = 
  transVal (nfCTC (nfCTC (\ x _ -> x)) x state)
  where
    transVal x = case consKind x of
                   Val       -> C_RichValue x
                   Failed    -> C_RichFail (toCurry (exceptions x))
                   Branching -> transBranching (orRef x) (branches x)

    transBranching _  []         = C_RichFail (C_ErrorCall List)
    transBranching _  [x]        = transVal x
    transBranching r  xs@(_:_:_) = C_RichChoice (C_OrRef r)
                                            (fromHaskellList (map transVal xs))

instance ConvertCH C_Exception Exception where
  toCurry (ErrorCall s)        = C_ErrorCall (toCurry s)
  toCurry (PatternMatchFail s) = C_PatternMatchFail (toCurry s)
  toCurry (AssertionFailed s)  = C_AssertionFailed (toCurry s)
  toCurry (IOException s)      = C_IOException (toCurry s)
  toCurry PreludeFailed        = C_PreludeFailed

  fromCurry (C_ErrorCall s)        = ErrorCall (fromCurry s)
  fromCurry (C_PatternMatchFail s) = PatternMatchFail (fromCurry s)
  fromCurry (C_AssertionFailed s)  = AssertionFailed (fromCurry s)
  fromCurry (C_IOException s)      = IOException (fromCurry s)
  fromCurry C_PreludeFailed        = PreludeFailed

---------------------------------------------------------------------------------
-- parallel search
---------------------------------------------------------------------------------

parallelSearch :: Curry a => a -> Result (C_IO (List a))
parallelSearch v _ = C_IO (\state -> do
  chan <- newChan
  mvar <- newEmptyMVar
  qsem <- newMyQSem 0
  tid <- forkIO (searchThread qsem mvar chan 
                              (nfCTC (nfCTC (\ x _ -> x)) v state))
  putMVar mvar [tid]
  --addFinalizer res (stopSearch mvar2)
  res <- myGetChanContents qsem chan
  Prelude.return (IOVal (fromHaskellList res)))


myGetChanContents :: Show a => MyQSem -> Chan (Maybe a) -> IO [a]
myGetChanContents qsem chan =
  unsafeInterleaveIO ( do
    decMyQSem qsem
    x <- readChan chan
    case x of
         Nothing -> Prelude.return []
         Just y -> do
            xs <- myGetChanContents qsem chan
            Prelude.return (y:xs) )


stopSearch :: MVar [ThreadId] -> IO ()
stopSearch mvar = do
  print "start"
  ids <- takeMVar mvar
  mapM_ killThread ids
  --putMVar mvar []


removeId :: MVar [ThreadId] -> Chan (Maybe a) -> ThreadId -> IO ()
removeId mvar chan tid = do
  ids <- takeMVar mvar
  let newids = delete tid ids
  case newids of
       [] -> writeChan chan Nothing -- >> putMVar mvar []
       _  -> putMVar mvar newids 


searchThread :: Curry a => MyQSem -> MVar [ThreadId] -> Chan (Maybe a) 
             -> a -> IO ()
searchThread qsem mvar chan x = do
  case consKind x of
    Val       -> incMyQSem qsem >> writeChan chan (Just x) >> terminate
    Failed    -> terminate
    Branching -> do
      --yield
      testMyQSem qsem
      let b:bs = branches x
      -- to prevent the threads from terminating till their Ids are registered
      ids <- takeMVar mvar  
      newIds <- mapM (forkIO . searchThread qsem mvar chan) bs
      putMVar mvar (newIds++ids)
      searchThread qsem mvar chan b
 where
  noThreads = do
    ids <- takeMVar mvar
    putStrLn ("noThreads: " ++ show (length ids))
    putMVar mvar ids
  terminate = do
    tid <- myThreadId
    removeId mvar chan tid

newtype MyQSem = MyQSem (MVar (Int, [MVar ()]))

-- |Build a new 'MyQSem'
newMyQSem :: Int -> IO MyQSem
newMyQSem init = do
   sem <- newMVar (init,[])
   Prelude.return (MyQSem sem)


-- |Wait for a unit to become available
incMyQSem :: MyQSem -> IO ()
incMyQSem (MyQSem sem) = do
   (avail,blocked) <- takeMVar sem
   putMVar sem (avail+1,blocked)


-- |Signal that a unit of the 'MyQSem' is available
decMyQSem :: MyQSem -> IO ()
decMyQSem (MyQSem sem) = do
   (avail,blocked) <- takeMVar sem
   if avail>0 then putMVar sem (avail-1,blocked)
              else mapM_ (flip putMVar ()) blocked >> putMVar sem (avail-1,[]) 


testMyQSem :: MyQSem -> IO ()
testMyQSem (MyQSem sem) = do
   x@(avail,blocked) <- takeMVar sem
   if avail<0 then putMVar sem x
              else do
                block <- newEmptyMVar
                putMVar sem (avail,block:blocked)
                takeMVar block

-------------------------------
-- covering non-determinism
-------------------------------

cover :: Curry a => a -> Result a
cover x st = case consKind x of
              Branching -> branching (Curry.RunTimeSystem.cover (orRef x)) 
                                     (map (flip Curry.Module.Meta.cover st) (branches x))
              _ -> x

-----------------------------------
-- encapsulate to head normal form
-----------------------------------

st :: Curry a => a -> Result (C_SearchTree a)
st x s = transVal (hnfCTC (\ x _ -> x) x s)
  where
    transVal x = case consKind x of
        Val       -> C_Value x
        Failed    -> C_Fail
        Branching -> let ref = orRef x in 
          if   isCovered ref
          then C_SearchTreeOr (uncover ref) (map (flip st s) (branches x))
          else C_Choice (fromHaskellList (map transVal (branches x)))

-----------------------------------
-- encapsulate to head normal form
-----------------------------------

richST :: Curry a => a -> Result (C_RichSearchTree a)
richST x s = transVal (hnfCTC (\ x _ -> x) x s)
  where
    transVal x = case consKind x of
        Val       -> C_RichValue x
        Failed    -> C_RichFail (toCurry (exceptions x))
        Branching -> let ref = orRef x in 
          if   isCovered ref
          then C_RichSearchTreeOr (uncover ref) 
                                  (map (flip richST s) (branches x))
          else C_RichChoice (C_OrRef (orRef x))
                        (fromHaskellList (map transVal (branches x)))

-----------------------------
-- the general question mark
-----------------------------

ors :: Curry a => List a -> Result a
ors xs _ = branching (error "Unsafe.ors") (toHaskellList xs)


-- temporarily added

prim_throw :: Curry a => C_Exception -> Result a
prim_throw e _ = Curry.RunTimeSystem.failed (fromCurry e)