packages feed

objective (empty) → 0.0

raw patch · 5 files changed

+145/−0 lines, 5 filesdep +basedep +comonaddep +transformerssetup-changed

Dependencies added: base, comonad, transformers, trivia

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2014, Fumiaki Kinoshita
+
+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.
+
+    * 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.
+
+    * Neither the name of Fumiaki Kinoshita nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple
+main = defaultMain
+ objective.cabal view
@@ -0,0 +1,25 @@+-- Initial objective.cabal generated by cabal init.  For further 
+-- documentation, see http://haskell.org/cabal/users-guide/
+
+name:                objective
+version:             0.0
+synopsis:            Extensible objects
+-- description:         
+homepage:            https://github.com/fumieval/objective
+license:             BSD3
+license-file:        LICENSE
+author:              Fumiaki Kinoshita
+maintainer:          Fumiaki Kinoshita <fumiexcel@gmail.com>
+-- copyright:           
+category:            Control
+build-type:          Simple
+-- extra-source-files:  
+cabal-version:       >=1.10
+
+library
+  exposed-modules:     Control.Object, Control.Monad.Objective.Class
+  -- other-modules:       
+  other-extensions:    MultiParamTypeClasses, KindSignatures, TypeFamilies
+  build-depends:       base >=4.5 && <5, trivia, comonad, transformers >= 0.3 && <0.5
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+ src/Control/Monad/Objective/Class.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE TypeFamilies #-}
+
+module Control.Monad.Objective.Class where
+import Control.Object
+import Control.Monad.Trans.State
+
+infix 3 .-
+infix 3 .&
+
+class Monad m => MonadObjective s m where
+  type Base m :: * -> *
+  data Control s (e :: * -> *)
+  -- | Send a message to the pointed one.
+  (.-) :: Control s e -> e a -> m a
+  -- | Add an object to the environment.
+  invoke :: Object e (Base m) -> m (Control s e)
+
+(.&) :: (MonadObjective k m, Stateful s e) => Control k e -> StateT s m a -> m a
+c .& m = do
+  s <- c .- get_
+  (a, s') <- runStateT m s
+  c .- put_ s'
+  return a
+ src/Control/Object.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FlexibleInstances #-}
+{-# LANGUAGE DeriveFunctor, DeriveDataTypeable #-}
+module Control.Object where
+
+import Control.Comonad.Zero
+import Control.Comonad
+import Control.Monad.Trans.State
+import Control.Monad
+import Data.Typeable
+
+-- | The type 'Object e m' represents objects which can handle messages 'e', perform actions in the 'Monad' 'm'.
+-- It can be thought of as a function where both domain and codomain are effects.
+-- Thus, it can be composed just like functions using '(.>>.)' (not often needed); the identity element is `echo`.
+newtype Object e m = Object { runObject :: forall x. e x -> m (x, Object e m) } deriving Typeable
+
+-- | Change the workspace of the object.
+transObject :: Monad n => (forall x. m x -> n x) -> Object e m -> Object e n
+transObject f (Object m) = Object $ liftM (fmap (transObject f)) . f . m
+
+-- | Apply a function to the messages coming into the object.
+adaptObject :: Monad m => (forall x. e x -> f x) -> Object f m -> Object e m
+adaptObject f (Object m) = Object $ liftM (fmap (adaptObject f)) . m . f
+
+-- | Parrots messages given.
+echo :: Functor e => Object e e
+echo = Object (fmap (\x -> (x, echo)))
+
+-- | Compose two objects (aka Dependency Injection).
+(.>>.) :: Monad n => Object e m -> Object m n -> Object e n
+Object m .>>. Object n = Object $ \e -> liftM (\((x, m'), n') -> (x, m' .>>. n')) $ n (m e)
+
+-- | Build an object.
+oneshot :: (Functor e, Monad m) => (forall a. e (m a) -> m a) -> Object e m
+oneshot m = go where
+  go = Object $ \e -> m (fmap return e) >>= \a -> return (a, go)
+{-# INLINE oneshot #-}
+
+-- | Build a stateful object.
+stateful :: (Functor e, Monad m) => (forall a. e (StateT s m a) -> StateT s m a) -> s -> Object (AccessT s e) m
+stateful m = go where
+  go s = Object $ \k -> liftM (fmap go) $ case k of
+    LiftAccessT e -> runStateT (m (fmap return e)) s
+    Get cont -> return (cont s, s)
+    Put s' cont -> return (cont, s')
+{-# INLINE stateful #-}
+
+-- | Like 'MonadState', but doesn't require 'Monad' as a prerequisite.
+class Stateful s f where
+  get_ :: f s
+  put_ :: s -> f ()
+
+-- | Inflicts external state accessibility to arbitrary effects.
+data AccessT s f a = Get (s -> a) | Put s a | LiftAccessT (f a) deriving (Functor, Typeable)
+
+instance Stateful s (AccessT s f) where
+  get_ = Get id
+  put_ s = Put s ()
+
+variable :: Monad m => s -> Object (AccessT s Zero) m
+variable s = Object $ \x -> case x of
+  Get cont -> return (cont s, variable s)
+  Put s' cont -> return (cont, variable s')
+  LiftAccessT e -> return (extract e, variable s)