packages feed

hactor 0.1.0.0 → 1.0.0.0

raw patch · 4 files changed

+205/−387 lines, 4 filesdep +stmdep +stm-chansdep ~basedep ~containersdep ~mtlPVP ok

version bump matches the API change (PVP)

Dependencies added: stm, stm-chans

Dependency ranges changed: base, containers, mtl

API changes (from Hackage documentation)

- Control.Concurrent.Actor: Case :: (m -> ActorM ()) -> Handler
- Control.Concurrent.Actor: Default :: (ActorM ()) -> Handler
- Control.Concurrent.Actor: TrapActorExceptions :: Flag
- Control.Concurrent.Actor: clearFlag :: Flag -> ActorM ()
- Control.Concurrent.Actor: data ActorException
- Control.Concurrent.Actor: data ActorExit
- Control.Concurrent.Actor: data Address
- Control.Concurrent.Actor: data Flag
- Control.Concurrent.Actor: data Handler
- Control.Concurrent.Actor: instance Enum Flag
- Control.Concurrent.Actor: instance Eq Address
- Control.Concurrent.Actor: instance Eq Flag
- Control.Concurrent.Actor: instance Exception ActorException
- Control.Concurrent.Actor: instance Exception ActorExit
- Control.Concurrent.Actor: instance Ord Address
- Control.Concurrent.Actor: instance Show ActorException
- Control.Concurrent.Actor: instance Show ActorExit
- Control.Concurrent.Actor: instance Show Address
- Control.Concurrent.Actor: instance Show Message
- Control.Concurrent.Actor: instance Typeable ActorException
- Control.Concurrent.Actor: instance Typeable ActorExit
- Control.Concurrent.Actor: instance Typeable Address
- Control.Concurrent.Actor: instance Typeable Context
- Control.Concurrent.Actor: instance Typeable Message
- Control.Concurrent.Actor: kill :: Address -> ActorM ()
- Control.Concurrent.Actor: link :: Address -> ActorM ()
- Control.Concurrent.Actor: monitor :: Address -> ActorM ()
- Control.Concurrent.Actor: receiveWithTimeout :: Int -> [Handler] -> ActorM () -> ActorM ()
- Control.Concurrent.Actor: setFlag :: Flag -> ActorM ()
- Control.Concurrent.Actor: spawn :: Actor -> IO Address
- Control.Concurrent.Actor: status :: Address -> ActorM ThreadStatus
- Control.Concurrent.Actor: testFlag :: Flag -> ActorM Bool
- Control.Concurrent.Actor: toggleFlag :: Flag -> ActorM ()
- Control.Concurrent.Actor: type Actor = ActorM ()
+ Control.Concurrent.Actor: actorThread :: ActorMessage msg => ActorHandle msg -> ThreadId
+ Control.Concurrent.Actor: class ActorMessage msg
+ Control.Concurrent.Actor: data ActorMessage msg => ActorHandle msg
+ Control.Concurrent.Actor: instance ActorMessage ()
+ Control.Concurrent.Actor: receiveMaybe :: ActorMessage msg => ActorM msg (Maybe msg)
+ Control.Concurrent.Actor: sendIO :: ActorMessage msg => ActorHandle msg -> msg -> IO ()
+ Control.Concurrent.Actor: spawnActor :: ActorMessage msg => ActorM msg () -> IO (ActorHandle msg)
- Control.Concurrent.Actor: receive :: [Handler] -> ActorM ()
+ Control.Concurrent.Actor: receive :: ActorMessage msg => ActorM msg (msg)
- Control.Concurrent.Actor: runActor :: Actor -> IO ()
+ Control.Concurrent.Actor: runActor :: ActorMessage msg => ActorM msg () -> IO ()
- Control.Concurrent.Actor: self :: ActorM Address
+ Control.Concurrent.Actor: self :: ActorMessage msg => ActorM msg (ActorHandle msg)
- Control.Concurrent.Actor: send :: Typeable m => Address -> m -> ActorM ()
+ Control.Concurrent.Actor: send :: (ActorMessage msg, ActorMessage msg') => ActorHandle msg -> msg -> ActorM msg' ()
- Control.Concurrent.Actor: type ActorM = ReaderT Context IO
+ Control.Concurrent.Actor: type ActorM msg = ReaderT (ActorContext msg) IO

Files

Control/Concurrent/Actor.hs view
@@ -1,379 +1,191 @@ -- | -- Module      :  Control.Concurrent.Actor--- Copyright   :  (c) 2014 Alex Constandache & Forkk--- License     :  BSD3+-- Copyright   :  (c) 2014 Forkk+-- License     :  MIT -- Maintainer  :  forkk@forkk.net -- Stability   :  experimental -- Portability :  GHC only (requires throwTo) ----- This module implements Erlang-style actors--- (what Erlang calls processes). It does not implement--- network distribution (yet?). Here is an example:+-- This module implements Erlang-style actors (what Erlang calls processes). -- -- @---act1 :: Actor---act1 = do---    me <- self---    liftIO $ print "act1 started"---    forever $ receive---      [ Case $ \((n, a) :: (Int, Address)) ->---            if n > 10000---                then do---                    liftIO . throwIO $ NonTermination---                else do---                    liftIO . putStrLn $ "act1 got " ++ (show n) ++ " from " ++ (show a)---                    send a (n+1, me)---      , Case $ \(e :: RemoteException) ->---            liftIO . print $ "act1 received a remote exception"---      , Default $ liftIO . print $ "act1: received a malformed message"---      ]------act2 :: Address -> Actor---act2 addr = do---    monitor addr---    -- setFlag TrapRemoteExceptions---    me <- self---    send addr (0 :: Int, me)---    forever $ receive---      [ Case $ \((n, a) :: (Int, Address)) -> do---                    liftIO . putStrLn $ "act2 got " ++ (show n) ++ " from " ++ (show a)---                    send a (n+1, me)---      , Case $ \(e :: RemoteException) ->---            liftIO . print $ "act2 received a remote exception: " ++ (show e)---      ]------act3 :: Address -> Actor---act3 addr = do---    monitor addr---    setFlag TrapRemoteExceptions---    forever $ receive---      [ Case $ \(e :: RemoteException) ->---            liftIO . print $ "act3 received a remote exception: " ++ (show e)---      ]------main = do---    addr1 <- spawn act1---    addr2 <- spawn (act2 addr1)---    spawn (act3 addr2)---    threadDelay 20000000--- @-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE ExistentialQuantification #-}-module Control.Concurrent.Actor (-  -- * Types-    Address-  , Handler(..)-  , ActorM-  , Actor-  , ActorException-  , ActorExit-  , Flag(..)-  -- * Actor actions-  , send-  , self-  , receive-  , receiveWithTimeout-  , spawn-  , runActor-  , monitor-  , link-  , kill-  , status-  , setFlag-  , clearFlag-  , toggleFlag-  , testFlag-  ) where+module Control.Concurrent.Actor+    -- * Types+    ( ActorHandle+    , ActorMessage+    , ActorM+    -- * Sending Messages+    , send+    , sendIO+    -- * Receiving Messages+    , receive+    , receiveMaybe+    -- * Spawning Actors+    , spawnActor+    , runActor+    -- * Getting Information+    , self+    , actorThread+    -- , monitor+    -- , link+    -- , kill+    -- , status+    -- , setFlag+    -- , clearFlag+    -- , toggleFlag+    -- , testFlag+    ) where  import Control.Concurrent-  ( forkIO-  , killThread-  , myThreadId-  , ThreadId-  )-import Control.Exception-  ( Exception(..)-  , SomeException-  , catches-  , throwTo-  , throwIO-  , PatternMatchFail(..)-  )-import qualified Control.Exception as E (Handler(..))-import Control.Concurrent.Chan-  ( Chan-  , newChan-  , readChan-  , writeChan-  )-import Control.Concurrent.MVar-  ( MVar-  , newMVar-  , modifyMVar_-  , withMVar-  , readMVar-  )-import GHC.Conc (ThreadStatus, threadStatus)+import Control.Concurrent.STM import Control.Monad.Reader-  ( ReaderT-  , runReaderT-  , asks-  , ask-  , liftIO-  )-import System.Timeout (timeout)-import Data.Dynamic-import Data.Set-  ( Set-  , empty-  , insert-  , delete-  , elems-  )-import Data.Word (Word64)-import Data.Bits (-    setBit-  , clearBit-  , complementBit-  , testBit-  ) --- | Exception raised by an actor on exit-data ActorExit = ActorExit deriving (Typeable, Show) -instance Exception ActorExit--data ActorException = ActorException Address SomeException-  deriving (Typeable, Show)--instance Exception ActorException--type Flags = Word64--data Flag = TrapActorExceptions-    deriving (Eq, Enum)--defaultFlags :: [Flag]-defaultFlags = []--setF :: Flag -> Flags -> Flags-setF = flip setBit . fromEnum+-- {{{ Types -clearF :: Flag -> Flags -> Flags-clearF = flip clearBit . fromEnum+-- {{{ Message -toggleF :: Flag -> Flags -> Flags-toggleF = flip complementBit . fromEnum+-- | The `ActorMessage` class must be implemented by any type that will be sent+-- as a message to actors.+-- Any given type of actor will have one `ActorMessage` type that is sent to+-- that actor. This ensures type safety.+-- Currently this is simply a dummy class with nothing in it, but things may be+-- added in the future.+class ActorMessage msg -isSetF :: Flag -> Flags -> Bool-isSetF = flip testBit . fromEnum+-- Allow actors that don't take messages.+instance ActorMessage () -data Context = Context-  { ctxMonitors :: MVar (Set Address)-  , ctxChan     :: Chan Message-  , ctxFlags    :: MVar Flags-  } deriving (Typeable)+-- }}} -newtype Message = Msg { unMsg :: Dynamic }-    deriving (Typeable)+-- {{{ Handle and context -instance Show Message where-    show = show . unMsg+-- | An `ActorHandle` acts as a reference to a specific actor.+data ActorMessage msg => ActorHandle msg = ActorHandle+    { ahContext     :: ActorContext msg     -- Context for this handle's actor.+    , ahThread      :: ThreadId             -- The actor's thread ID.+    } -toMsg :: Typeable a => a -> Message-toMsg = Msg . toDyn+-- | The `ActorContext` holds shared information about a given actor.+-- This is information such as the actor's mail box, the list of actors it's+-- linked to, etc.+data ActorMessage msg => ActorContext msg = ActorContext+    { acMailBox :: MailBox msg  -- Channel for the actor's messages.+    } -fromMsg :: Typeable a => Message -> Maybe a-fromMsg = fromDynamic . unMsg+-- | The type for the actor's mail box.+type MailBox msg = TChan msg --- | The address of an actor, used to send messages-data Address = Address-  { addrThread  :: ThreadId-  , addrContext :: Context-  } deriving (Typeable)+-- }}} -instance Show Address where-    show (Address ti _) = "Address(" ++ (show ti) ++ ")"+-- }}} -instance Eq Address where-    addr1 == addr2 = (addrThread addr1) == (addrThread addr2)+-- | The base actor monad.+type ActorM msg = ReaderT (ActorContext msg) IO -instance Ord Address where-    addr1 `compare` addr2 = (addrThread addr1) `compare` (addrThread addr2)+-- {{{ Get info --- | The actor monad, just a reader monad on top of 'IO'.-type ActorM = ReaderT Context IO+-- | Gets a handle to the current actor.+self :: ActorMessage msg => ActorM msg (ActorHandle msg)+self = do+    context <- ask+    thread <- liftIO $ myThreadId+    return $ ActorHandle context thread --- | The type of an actor. It is just a monadic action--- in the 'ActorM' monad, returning ()-type Actor = ActorM ()+-- | Retrieves the mail box for the current actor.+myMailBox :: ActorMessage msg => ActorM msg (MailBox msg)+myMailBox = asks acMailBox -data Handler = forall m . (Typeable m)-             => Case (m -> ActorM ())-             |  Default (ActorM ())+-- }}} --- | Used to obtain an actor's own address inside the actor-self :: ActorM Address-self = do-    c <- ask-    i <- liftIO myThreadId-    return $ Address i c+-- {{{ Receiving --- | Try to handle a message using a list of handlers.--- The first handler matching the type of the message--- is used.-receive :: [Handler] -> ActorM ()-receive hs = do-    ch  <- asks ctxChan-    msg <- liftIO . readChan $ ch-    rec msg hs+-- | Reads a message from the actor's mail box.+-- If there are no messages, blocks until one is received. If you don't want+-- this, use `receiveMaybe` instead.+receive :: ActorMessage msg => ActorM msg (msg)+receive = do+    chan <- myMailBox+    -- Read from the channel, retrying if there is nothing to read.+    liftIO $ atomically $ readTChan chan --- | Same as receive, but times out after a specified--- amount of time and runs a default action-receiveWithTimeout :: Int -> [Handler] -> ActorM () -> ActorM ()-receiveWithTimeout n hs act = do-    ch <- asks ctxChan-    msg <- liftIO . timeout n . readChan $ ch-    case msg of-        Just m  -> rec m hs-        Nothing -> act+-- | Reads a message from the actor's mail box.+-- If there are no messages, returns `Nothing`.+receiveMaybe :: ActorMessage msg => ActorM msg (Maybe msg)+receiveMaybe = do+    chan <- myMailBox+    liftIO $ atomically $ tryReadTChan chan -rec :: Message -> [Handler] -> ActorM ()-rec msg [] = liftIO . throwIO $ PatternMatchFail err where-    err = "no handler for messages of type " ++ (show msg)-rec msg ((Case hdl):hs) = case fromMsg msg of-    Just m  -> hdl m-    Nothing -> rec msg hs-rec _ ((Default act):_) = act+-- }}} +-- {{{ Sending --- | Sends a message from inside the 'ActorM' monad-send :: Typeable m => Address -> m -> ActorM ()-send addr msg = do-    let ch = ctxChan . addrContext $ addr-    liftIO . writeChan ch . toMsg $ msg+-- | Sends a message to the given actor handle.+-- This is secretly just `sendIO` lifted into an actor monad.+send :: (ActorMessage msg, ActorMessage msg') =>+        ActorHandle msg -> msg -> ActorM msg' ()+send hand msg = liftIO $ sendIO hand msg --- FIXME: This is a big and complicated function. It would be a good idea to--- break it up into smaller parts.--- | Prepares the given actor monad to be run as an actor. Returns a tuple--- containing the actor's context and an IO action to run the actor.-mkActor :: Actor -> [Flag] -> IO (IO (), Context)-mkActor actor flagList = do-    chan <- liftIO newChan-    linkedActors <- newMVar empty-    flags <- newMVar $ foldl (flip setF) 0x00 flagList-    let context = Context linkedActors chan flags-    -- An IO action which executes the actual actor.-    let actorFunc = actorInternal `catches` [ E.Handler linkedHandler-                                            , E.Handler exceptionHandler]-    -- The internal IO action for the actor.-    -- This will be wrapped by exception handlers.-        actorInternal = runReaderT actor context-    -- Linked exception handler. Catches exceptions from linked actors and-    -- handles them appropriately.-        linkedHandler :: ActorException -> IO ()-        linkedHandler ex@(ActorException addr iex) = do-            -- Remove the linked actor from our list.-            modifyMVar_ linkedActors (return . delete addr)-            me <- myThreadId-            forward $ ActorException (Address me context) iex-            throwIO ex-    -- Exception handler. Catches all exceptions and forwards them to-    -- monitoring actors.-        exceptionHandler :: SomeException -> IO ()-        exceptionHandler ex = do-            me <- myThreadId-            forward $ ActorException (Address me context) ex-            throwIO ex-    -- Exception forwarding function.-    -- Takes an `ActorException` and forwards it to all actors monitoring the-    -- current actor.-        forward :: ActorException -> IO ()-        forward ex = do-            linkedSet <- readMVar linkedActors-            mapM_ (forwardTo ex) $ elems linkedSet-    -- Forwards the given exception to the given actor.-        forwardTo :: ActorException -> Address -> IO ()-        forwardTo ex addr = do-            let remoteFlags = ctxFlags . addrContext $ addr-                remoteChan  = ctxChan  . addrContext $ addr-            trap <- withMVar remoteFlags (return . isSetF TrapActorExceptions)-            -- If the remote actor is trapping actor exceptions, send our-            -- exception to it as a message. Otherwise, throw it to the actor's-            -- thread.-            if trap-               then writeChan remoteChan $ toMsg ex-               else throwTo (addrThread addr) ex-    -- Return the context and the IO action.-    return (actorFunc, context)+-- | Sends a message to the given actor handle from within the IO monad.+sendIO :: ActorMessage msg => ActorHandle msg -> msg -> IO ()+sendIO hand msg =+    atomically $ writeTChan mailBox $ msg+  where+    mailBox = handleMailBox hand +-- }}} --- | Spawn a new actor with default flags on a separate thread.-spawn :: Actor -> IO Address-spawn actor = do-    (actorFunc, context) <- mkActor actor defaultFlags-    -- Start the actor's thread.-    threadId <- forkIO actorFunc-    -- Return a handle.-    return $ Address threadId context+-- {{{ Spawning --- | Run the given actor with default flags on the current thread.--- This can be useful for your program's "main actor".-runActor :: Actor -> IO ()-runActor actor = do-    -- Create the actor.-    (actorFunc, _) <- mkActor actor defaultFlags-    actorFunc+-- | Internal function for starting actors.+-- This takes an `ActorM` action, makes a channel for it, wraps it in exception+-- handling stuff, and turns it into an IO monad. The function returns a tuple+-- containing the actor's context and the IO action to execute the actor.+wrapActor :: ActorMessage msg => ActorM msg () -> IO (IO (), ActorContext msg)+wrapActor actorAction = do+    -- TODO: Exception handling.+    -- First, create a channel for the actor.+    chan <- atomically newTChan+    -- Next, create the context and run the ReaderT action.+    let context = ActorContext chan+        ioAction = runReaderT actorAction context+    -- Return the information.+    return (ioAction, context)  --- | Monitors the actor at the specified address.--- If an exception is raised in the monitored actor's--- thread, it is wrapped in an 'ActorException' and--- forwarded to the monitoring actor. If the monitored--- actor terminates, an 'ActorException' is raised in--- the monitoring Actor-monitor :: Address -> ActorM ()-monitor addr = do-    me <- self-    let mons = ctxMonitors . addrContext $ addr-    liftIO $ modifyMVar_ mons (return . insert me)---- | Like `monitor`, but bi-directional-link :: Address -> ActorM ()-link addr = do-    monitor addr-    mons <- asks ctxMonitors-    liftIO $ modifyMVar_ mons (return . insert addr)+-- | Spawns the given actor on another thread and returns a handle to it.+spawnActor :: ActorMessage msg => ActorM msg () -> IO (ActorHandle msg)+spawnActor actorAction = do+    -- Wrap the actor action.+    (ioAction, context) <- wrapActor actorAction+    -- Fork the actor's IO action to another thread.+    thread <- forkIO ioAction+    -- Return the handle.+    return $ ActorHandle context thread --- | Kill the actor at the specified address-kill :: Address -> ActorM ()-kill = liftIO . killThread . addrThread+-- | Runs the given actor on the current thread.+-- This function effectively turns the current thread into the actor's thread.+-- Obviously, this means that this function will block until the actor exits.+-- You probably want to use this for your "main" actor.+runActor :: ActorMessage msg => ActorM msg () -> IO ()+runActor actorAction = do+    -- Wrap the actor action. We discard the context, because we won't be+    -- returning a handle to this actor.+    (ioAction, _) <- wrapActor actorAction+    -- Execute the IO action on the current thread.+    ioAction --- | The current status of an actor-status :: Address -> ActorM ThreadStatus-status = liftIO . threadStatus . addrThread+-- }}} --- | Sets the specified flag in the actor's environment-setFlag :: Flag -> ActorM ()-setFlag flag = do-    fs <- asks ctxFlags-    liftIO $ modifyMVar_ fs (return . setF flag)+-- {{{ Utility functions --- | Clears the specified flag in the actor's environment-clearFlag :: Flag -> ActorM ()-clearFlag flag = do-    fs <- asks ctxFlags-    liftIO $ modifyMVar_ fs (return . clearF flag)+-- | Gets the mail box for the given handle.+handleMailBox :: ActorMessage msg => ActorHandle msg -> MailBox msg+handleMailBox = acMailBox . ahContext --- | Toggles the specified flag in the actor's environment-toggleFlag :: Flag -> ActorM ()-toggleFlag flag = do-    fs <- asks ctxFlags-    liftIO $ modifyMVar_ fs (return . toggleF flag)+-- | Gets the thread ID for the given actor handle.+actorThread :: ActorMessage msg => ActorHandle msg -> ThreadId+actorThread = ahThread --- | Checks if the specified flag is set in the actor's environment-testFlag :: Flag -> ActorM Bool-testFlag flag = do-    fs <- asks ctxFlags-    liftIO $ withMVar fs (return . isSetF flag)+-- }}} 
LICENSE view
@@ -1,30 +1,20 @@-Copyright Alex Constandache & Forkk 2014--All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are met:--    * Redistributions of source code must retain the above copyright-      notice, this list of conditions and the following disclaimer.+Copyright (c) 2014 Forkk -    * Redistributions in binary form must reproduce the above-      copyright notice, this list of conditions and the following-      disclaimer in the documentation and/or other materials provided-      with the distribution.+Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions: -    * Neither the names of Forkk, Alex Constandache, or any other-      contributors may be used to endorse or promote products derived-      from this software without specific prior written permission.+The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,10 @@+Hactor+======++Hactor is a library which aims to provide lightweight actors similar to Erlang+processes.++This project is inspired by, and was originally a fork of+[thespian](https://hackage.haskell.org/package/thespian), but I decided that it+would be better and easier to just rewrite it.+
hactor.cabal view
@@ -1,66 +1,72 @@ -- The name of the package.-name:                hactor+name: hactor --- The package version. See the Haskell package versioning policy--- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for--- standards guiding when and how versions should be incremented.-version:             0.1.0.0+-- The package version.  See the Haskell package versioning policy (PVP) +-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary:+--       +-+------- breaking API changes+--       | | +----- non-breaking API additions+--       | | | +--- code changes with no API change+version: 1.0.0.0  -- A short (one-line) description of the package.-synopsis:            Lightweight Erlang-style actors for Haskell.+synopsis: Lightweight Erlang-style actors for Haskell.  -- A longer description of the package.-description: This is a fork of Thespian, a library which aims to provide lightweight Erlang-style actors for Haskell.+description: Hactor is a library which aims to provide lightweight Erlang-style actors for Haskell.  -- URL for the project homepage or repository.-homepage:            https://github.com/Forkk/hactor+homepage: https://github.com/Forkk/hactor  -- The license under which the package is released.-license:             BSD3+license: MIT  -- The file containing the license text.-license-file:        LICENSE+license-file: LICENSE  -- The package author(s).-author: Alex Constandache, Forkk+author: Forkk  -- An email address to which users can send suggestions, bug reports, -- and patches.-maintainer:          forkk@forkk.net+maintainer: forkk@forkk.net  -- A copyright notice.--- Copyright:           +copyright: Copyright Forkk 2014  -- Stability of the pakcage (experimental, provisional, stable...)-stability:           experimental--category:            Concurrency--build-type:          Simple+stability: experimental+category: Concurrency+build-type: Simple  -- Extra files to be distributed with the package, such as examples or -- a README.--- Extra-source-files:  +extra-source-files: README.md  -- Constraint on the version of Cabal needed to build this package.-cabal-version:       >=1.2-+cabal-version: >=1.20  library   -- Modules exported by the library.-  exposed-modules:     Control.Concurrent.Actor+  exposed-modules: Control.Concurrent.Actor      -- Packages needed in order to build this package.-  build-depends:       base >= 3 && < 5, -                       mtl >= 1.1,-                       containers+  build-depends:+      base                          >=4.7     && <4.8+    , mtl                           >=2.2     && <2.3+    , stm                           >=2.4     && <2.5+    , stm-chans                     >=3.0     && <3.1+    , containers                    >=0.5     && <0.6    -- Extra options for ghc-  ghc-options:         -Wall+  ghc-options: -Wall      -- Modules not exported by this package.-  -- Other-modules:       +  -- other-modules:      -- Extra tools (e.g. alex, hsc2hs, ...) needed to build the source.-  -- Build-tools:         +  -- build-tools:++  default-language: Haskell2010