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 +5/−0
- LICENSE +20/−0
- changeset-reflex.cabal +69/−0
- src/Control/Monad/Changeset/Reflex.hs +78/−0
+ 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)