packages feed

concur-core (empty) → 0.1.0.0

raw patch · 10 files changed

+313/−0 lines, 10 filesdep +basedep +freedep +mtlsetup-changed

Dependencies added: base, free, mtl, natural-transformation, stm, transformers

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (C) 2017 Anupam Jain++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 Anupam Jain 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.
+ README.md view
@@ -0,0 +1,1 @@+# concur-core
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ concur-core.cabal view
@@ -0,0 +1,48 @@+-- This file has been generated from package.yaml by hpack version 0.28.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 17db59d45076972dd7ba6d55b12cc5b23efd0eece58a6a855284b6f1f7e8fff8++name:                concur-core+version:             0.1.0.0+synopsis:            A client side web UI framework for Haskell. Core framework.+description:         A client side web UI framework for Haskell. Core framework.+homepage:            https://github.com/ajnsit/concur#readme+bug-reports:         https://github.com/ajnsit/concur/issues+license:             BSD3+license-file:        LICENSE+author:              Anupam Jain+maintainer:          ajnsit@gmail.com+copyright:           2017 (C) All Rights Reserved.+category:            Web+build-type:          Simple+cabal-version:       >= 1.10+extra-source-files:+    README.md++source-repository head+  type: git+  location: https://github.com/ajnsit/concur++library+  ghc-options: -Wall -ferror-spans+  default-language: Haskell2010+  hs-source-dirs:+      src+  exposed-modules:+      Concur.Core+      Concur.Core.Types+      Concur.Core.Notify+      Control.MonadSTM+      Control.ShiftMap+      Control.MultiAlternative+  other-modules:+      Paths_concur_core+  build-depends:+      base >=4.7 && <5+    , free >=4.12+    , mtl >=2.2+    , natural-transformation >=0.4+    , stm >=2.4+    , transformers >=0.5
+ src/Concur/Core.hs view
@@ -0,0 +1,6 @@+module Concur.Core+  ( module X+  ) where++import Concur.Core.Types as X+import Concur.Core.Notify as X
+ src/Concur/Core/Notify.hs view
@@ -0,0 +1,44 @@+module Concur.Core.Notify+  ( Notify+  , fetch+  , await+  , notify+  , newNotify+  , newNotifyIO+  ) where++import           Control.Concurrent.STM (STM, TVar, newTVar, newTVarIO,+                                         readTVar, retry, writeTVar)+import           Control.Monad          (void)++-- TODO: Use Weak TVar pointers as appropriate+newtype Notify a = Notify (TVar (Maybe a))++fetch :: Notify a -> STM (Maybe a)+fetch (Notify v) = tryTakeTVar v++await :: Notify a -> STM a+await (Notify v) = takeTVar v++notify :: Notify a -> a -> STM ()+notify (Notify v) a = void (writeTVar v (Just a))++newNotify :: STM (Notify a)+newNotify = Notify <$> newTVar Nothing++newNotifyIO :: IO (Notify a)+newNotifyIO = Notify <$> newTVarIO Nothing++takeTVar :: TVar (Maybe a) -> STM a+takeTVar t = do+  m <- readTVar t+  case m of+    Nothing -> retry+    Just a  -> do writeTVar t Nothing; return a++tryTakeTVar :: TVar (Maybe a) -> STM (Maybe a)+tryTakeTVar t = do+  m <- readTVar t+  case m of+    Nothing -> return Nothing+    Just a  -> do writeTVar t Nothing; return (Just a)
+ src/Concur/Core/Types.hs view
@@ -0,0 +1,130 @@+{-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE TupleSections              #-}+module Concur.Core.Types+  ( Widget(..)+  , continue+  , widget+  , display+  , mapView+  , wrapView+  , Suspend(..)+  , SuspendF(..)+  , Effect+  , effect+  , awaitViewAction+  , MultiAlternative(..)+  , loadWithIO+  , remoteWidget+  , unsafeBlockingIO+  ) where++import           Concur.Core.Notify       (Notify, await, newNotify, newNotifyIO, notify)+import           Control.Applicative      (Alternative, empty, (<|>))+import           Control.Concurrent       (forkIO)+import           Control.Concurrent.STM   (STM, atomically, retry)+import           Control.Monad            (MonadPlus (..))+import           Control.Monad.Free       (Free (..), hoistFree, liftF)+import           Control.Monad.IO.Class   (MonadIO, liftIO)+import           Control.MonadSTM         (MonadSTM (..))+import           Control.MultiAlternative (MultiAlternative, orr, never)++newtype Widget v a = Widget { suspend :: Free (Suspend v) a }+  deriving (Functor, Applicative, Monad)++data SuspendF v a = SuspendF { view :: v, cont :: Effect a }+  deriving Functor++newtype Suspend v a = Suspend { unSuspend :: IO (SuspendF v a) }+  deriving Functor++type Effect a = STM (Maybe a)++continue :: Suspend v a -> Widget v a+continue = Widget . liftF++widget :: v -> Effect a -> Widget v a+widget v r = continue $ Suspend $ return $ SuspendF v r++display :: v -> Widget v a+display v = widget v retry++-- Change the view of a Widget+mapView :: (u -> v) -> Widget u a -> Widget v a+mapView f (Widget w) = Widget $ go w+  where+    go = hoistFree g+    g (Suspend io) = Suspend $ fmap h io+    h (SuspendF v c) = SuspendF (f v) c++-- Generic widget view wrapper+wrapView :: Applicative f => (u -> v) -> Widget u a -> Widget (f v) a+wrapView f = mapView (pure . f)++-- A pure effect+effect :: v -> STM a -> Widget v a+effect v m = widget v $ Just <$> m++instance Monoid v => MonadSTM (Widget v) where+  liftSTM = effect mempty++-- | IMPORTANT: Blocking IO is dangerous as it can block the entire UI from updating.+--   It should only be used for *very* quick running IO actions like creating MVars.+unsafeBlockingIO :: Monoid v => IO a -> Widget v a+unsafeBlockingIO io = continue $ Suspend $ fmap (SuspendF mempty . return . Just) io++-- This is a safe use for blockingIO, and is exported+awaitViewAction :: (Notify a -> v) -> Widget v a+awaitViewAction f = continue $ Suspend $ do+  n <- newNotifyIO+  return $ SuspendF (f n) (fmap Just (await n))++loadWithIO :: v -> IO a -> Widget v a+loadWithIO v io = continue $ Suspend $ do+  n <- newNotifyIO+  _ <- forkIO $ io >>= atomically . notify n+  return $ SuspendF v (Just <$> await n)++-- Make a Widget, which can be pushed to remotely+remoteWidget :: (MultiAlternative m, MonadSTM m, Monad m) => m b -> (a -> m b) -> STM (a -> m (), m b)+remoteWidget d f = do+  var <- newNotify+  return (proxy var, wid var d)+  where+    proxy var = \a -> liftSTM $ notify var a+    wid var ui = orr [Left <$> ui, Right <$> (liftSTM $ await var)] >>= either return (wid var . f)++instance Monoid v => MonadIO (Widget v) where+  liftIO = loadWithIO mempty++-- IMPORTANT NOTE: This Alternative instance is NOT the same one as that for Free.+-- That one simply uses Alternative for Suspend. But that one isn't sufficient for us.+-- Verify laws:+--         Right distributivity (of <*>):  (f <|> g) <*> a = (f <*> a) <|> (g <*> a)+--         Right absorption (for <*>):  empty <*> a = empty+--         Left distributivity (of fmap):  f <$> (a <|> b) = (f <$> a) <|> (f <$> b)+--  OK     Left absorption (for fmap):  f <$> empty = empty+instance Monoid v => Alternative (Widget v) where+  empty = never+  f <|> g = orr [f,g]++instance Monoid v => MultiAlternative (Widget v) where+  never = display mempty+  orr = Widget . comb . map suspend+    where+      peelAllFree []           = Right []+      peelAllFree (Pure a : _) = Left a+      peelAllFree (Free s: fs) = fmap (s:) $ peelAllFree fs+      comb wfs = case peelAllFree wfs of+        Left a -> pure a+        Right fsio -> Free $ Suspend $ do+          fs <- mapM unSuspend fsio+          return $ SuspendF (mconcat $ map view fs) (merge $ map cont fs)+        where+          merge ws = do+            (i, me) <- foldl (\prev (i,w) -> prev <|> fmap (i,) w) retry $ zip [0..] ws+            return $ fmap (\e -> comb $ take i wfs ++ [e] ++ drop (i+1) wfs) me++-- The default instance derives from Alternative+instance Monoid v => MonadPlus (Widget v)
+ src/Control/MonadSTM.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE FlexibleInstances #-}+module Control.MonadSTM where++import           Control.Concurrent.STM (STM, atomically)+import           Control.Monad.Trans    (MonadTrans (..))++-- | Like `MonadIO` but for `STM` monad+-- `MonadBase` seemed too cumbersome for this.+class MonadSTM m where+  liftSTM :: STM a -> m a++instance MonadSTM IO where+  liftSTM = atomically++instance (MonadTrans t, Monad m, MonadSTM m) => MonadSTM (t m) where+  liftSTM = lift . liftSTM
+ src/Control/MultiAlternative.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE UndecidableInstances #-}+module Control.MultiAlternative where++import Control.Applicative (Alternative, empty, (<|>))++class MultiAlternative f where+  never :: f a+  orr :: [f a] -> f a++instance {-# OVERLAPPABLE #-} Alternative f => MultiAlternative f where+  never = empty+  orr = foldl (<|>) empty
+ src/Control/ShiftMap.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE TypeOperators         #-}+module Control.ShiftMap where++import           Control.Natural              (type (~>))++import           Control.Monad.State          (StateT, mapStateT)+import           Control.Monad.Trans.Identity (IdentityT, mapIdentityT)++-- | Mapping between Natural Transformations+class ShiftMap s t where+  shiftMap :: (s ~> s) -> (t ~> t)++instance ShiftMap m m where+  shiftMap = id++instance ShiftMap m (IdentityT m) where+  shiftMap = mapIdentityT++instance ShiftMap m (StateT s m) where+  shiftMap = mapStateT