packages feed

changeset-reflex (empty) → 0.1.0.0

raw patch · 4 files changed

+172/−0 lines, 4 filesdep +basedep +changesetdep +containers

Dependencies added: base, changeset, containers, dependent-map, monoid-extras, reflex, some

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for changeset++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2023 Manuel Bärenz++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:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++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.
+ changeset-reflex.cabal view
@@ -0,0 +1,69 @@+cabal-version: 3.0+name: changeset-reflex+-- PVP summary:     +-+------- breaking API changes+--                  | | +----- non-breaking API additions+--                  | | | +--- code changes with no API change+version: 0.1.0.0+synopsis: Stateful monad transformer based on monoidal actions+description:+  A general state monad transformer with separate types for the state and the possible changes.+  It can be defined for any monoid action.+  The monoid represents "changes", "updates", "edits" or "diffs" on the state.++  This package exposes utilities to propagate changes along @reflex@ events.++license: MIT+license-file: LICENSE+author: Manuel Bärenz+maintainer: programming@manuelbaerenz.de+copyright: MIT+category: Control+build-type: Simple+extra-doc-files: CHANGELOG.md++source-repository head+  type: git+  location: https://github.com/turion/changeset++flag dev+  description: Enable warnings as errors. Active on ci.+  default: False+  manual: True++common opts+  ghc-options:+    -Wall++  if flag(dev)+    ghc-options:+      -Werror+  default-extensions:+    BangPatterns+    DeriveFunctor+    FlexibleInstances+    FunctionalDependencies+    GADTs+    KindSignatures+    MultiParamTypeClasses+    NamedFieldPuns+    RankNTypes+    ScopedTypeVariables+    TupleSections+    TypeOperators++library+  import: opts+  exposed-modules:+    Control.Monad.Changeset.Reflex++  build-depends:+    base >=4.12 && <4.22,+    changeset ==0.1.0.0,+    containers >=0.6 && <0.8,+    dependent-map ^>=0.4,+    monoid-extras ^>=0.6,+    reflex >=0.8.2.1 && <0.10,+    some ^>=1.0.1,++  hs-source-dirs: src+  default-language: Haskell2010
+ src/Control/Monad/Changeset/Reflex.hs view
@@ -0,0 +1,78 @@+module Control.Monad.Changeset.Reflex where++-- base+import Data.Bifunctor (Bifunctor (second))+import Data.Functor ((<&>))+import Data.Functor.Compose+import Data.Functor.Identity (Identity (Identity))++-- monoid-extras+import Data.Monoid.Action++-- reflex+import Reflex.Class++-- dependent-map+import Data.Dependent.Map (+  DMap,+  delete,+  insert,+  traverseWithKey,+ )++-- changeset+import Control.Monad.Trans.Changeset (ChangesetT (..))+import Data.Function ((&))+import Data.Functor.Misc (dmapToIntMap, dmapToMap, intMapWithFunctorToDMap, mapWithFunctorToDMap)+import Data.GADT.Compare (GCompare)+import Data.IntMap (IntMap)+import qualified Data.IntMap as IM+import Data.List.NonEmpty (NonEmpty, fromList)+import Data.Map (Map)++-- | A change to a dependent map 'DMap'.+data DMapChange k f v+  = Insert (k v) (f v)+  | Delete (k v)++instance (GCompare k) => Action (DMapChange k f v) (DMap k f) where+  act (Insert k v) = insert k v+  act (Delete k) = delete k++{- | Merge changes from a 'DMap' of 'ChangesetT' computations performing events.++The initial state is the same for every change.++If several change events occur simultaneously, their changes are combined.+-}+mergeChangesetEvent :: (Reflex t, GCompare k, Monoid w) => DMap k (ChangesetT s w (Event t)) -> ChangesetT s w (Event t) (DMap k Identity)+mergeChangesetEvent dmap = ChangesetT $ \s -> traverseWithKey (const (second Identity)) <$> mergeG (`getChangesetT` s) dmap++-- | A functor that creates changes, and performs side effects in @m@ to create an 'Event'.+type ChangesetEventT t s w m = ChangesetT s w (Compose m (Event t))++-- | Like 'mergeChangesetEvent', but generalised to include @m@ effects.+mergeChangesetEventT :: (Reflex t, GCompare k, Monoid w, Applicative m) => DMap k (ChangesetEventT t s w m) -> ChangesetEventT t s w m (DMap k Identity)+mergeChangesetEventT dmap = ChangesetT $ \s ->+  Compose $+    fmap (traverseWithKey (const (second Identity)))+      . mergeG getCompose+      <$> traverseWithKey (const (fmap Compose . getCompose . flip getChangesetT s)) dmap++-- | Merge a 'Map' of changes+mergeChangesetMap :: (Reflex t, Monoid w, Applicative m, Ord k) => Map k (ChangesetEventT t s w m a) -> ChangesetEventT t s w m (Map k a)+mergeChangesetMap = fmap dmapToMap . mergeChangesetEventT . mapWithFunctorToDMap++-- | Merge an 'IntMap' of changes+mergeChangesetIntMap :: (Reflex t, Monoid w, Applicative m) => IntMap (ChangesetEventT t s w m a) -> ChangesetEventT t s w m (IntMap a)+mergeChangesetIntMap = fmap dmapToIntMap . mergeChangesetEventT . intMapWithFunctorToDMap++-- | Merge a list of changes+mergeChangesetEventTs :: (Reflex t, Monoid w, Applicative m) => [ChangesetEventT t s w m a] -> ChangesetEventT t s w m (NonEmpty a)+mergeChangesetEventTs [] = ChangesetT $ const $ Compose $ pure never+mergeChangesetEventTs cs =+  cs+    & zip [0 ..]+    & IM.fromDistinctAscList+    & mergeChangesetIntMap+    <&> (fromList . IM.elems)