packages feed

changeset-fused-effects (empty) → 0.2.1

raw patch · 5 files changed

+207/−0 lines, 5 filesdep +basedep +changesetdep +changeset-fused-effects

Dependencies added: base, changeset, changeset-fused-effects, falsify, fused-effects, monoid-extras, tasty, tasty-hunit

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for changeset++## 0.2.0++* First version. Contains `Change` and `Current` effects.
+ 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-fused-effects.cabal view
@@ -0,0 +1,79 @@+cabal-version: 3.0+name: changeset-fused-effects+version: 0.2.1+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 the corresponding effect signature for usage in @fused-effects@.++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+    FlexibleContexts+    FlexibleInstances+    FunctionalDependencies+    GADTs+    KindSignatures+    MultiParamTypeClasses+    NamedFieldPuns+    RankNTypes+    ScopedTypeVariables+    TupleSections+    TypeApplications+    TypeOperators++library+  import: opts+  exposed-modules:+    Control.Effect.Changeset++  build-depends:+    base >=4.16 && <4.23,+    changeset ==0.2.1,+    fused-effects ^>=1.1.2.3,++  hs-source-dirs: src+  default-language: Haskell2010++test-suite changeset-fused-effects-test+  import: opts+  default-language: Haskell2010+  type: exitcode-stdio-1.0+  hs-source-dirs: test+  main-is: Main.hs+  build-depends:+    base,+    changeset,+    changeset-fused-effects,+    falsify ^>=0.2,+    fused-effects,+    monoid-extras,+    tasty ^>=1.4.2,+    tasty-hunit ^>=0.10.2,
+ src/Control/Effect/Changeset.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -Wno-orphans #-}++{- | A fused-effects algebra for the 'Changeset' effect.++This module provides an effect type and algebra that mirror the API of+'Control.Monad.Changeset.Class.MonadChangeset'.+The 'Changeset' effect allows a computation to observe the current state+and to apply changes to it, using the right action of a monoid @w@ on a state type @s@.++See "Control.Monad.Trans.Changeset" for the full description of the changeset concept.++To use this effect, use 'sendChange' or 'sendCurrent'.+The effect is interpreted by the 'Control.Monad.Trans.Changeset.ChangesetT' transformer via its 'Algebra' instance.+-}+module Control.Effect.Changeset where++-- base+import Data.Bifunctor (first)+import Data.Kind (Type)++-- fused-effects+import Control.Algebra++-- changeset+import Control.Monad.Changeset.Class (MonadChangeset (..))+import Control.Monad.Trans.Changeset (ChangesetT (..))+import Data.Monoid.RightAction (RightAction)++-- | The 'Changeset' effect, parameterised by the state type @s@ and the change monoid @w@.+data Changeset s w (m :: Type -> Type) k where+  {- | Apply a change to the state.++  The 'RightAction' instance is used to mutate the state.+  -}+  Change :: w -> Changeset s w m ()+  -- | Observe the current state.+  Current :: Changeset s w m s++instance (RightAction w s, Monoid w, Algebra sig m) => Algebra (Changeset s w :+: sig) (ChangesetT s w m) where+  alg handler sig ctx = case sig of+    L (Change w) -> ctx <$ change w+    L Current -> (<$ ctx) <$> current+    R other -> ChangesetT $ \s ->+      thread ((\(w, x) -> first (mappend w) <$> getChangesetT x s) ~<~ handler) other (mempty, ctx)++{- | Send a 'Change' to the effect carrier.++A 'proxy' for @s@ is required to fix the state type unambiguously,+since @w@ alone may not determine @s@.+-}+sendChange :: forall s w sig m proxy. (Has (Changeset s w) sig m) => proxy s -> w -> m ()+sendChange _ = send . Change @_ @s++{- | Send a 'Current' to the effect carrier.++A 'proxy' for @w@ is required to fix the change type unambiguously,+since @s@ alone may not determine @w@.+-}+sendCurrent :: forall s w sig m proxy. (Has (Changeset s w) sig m) => proxy w -> m s+sendCurrent _ = send (Current @s @w)
+ test/Main.hs view
@@ -0,0 +1,42 @@+module Main (main) where++-- base+import Data.Proxy (Proxy (..))++-- tasty+import Test.Tasty++-- tasty-hunit+import Test.Tasty.HUnit (testCase, (@?=))++-- fused-effects+import Control.Algebra (Has)++-- changeset+import Control.Monad.Changeset.Class (MonadChangeset (..))+import Control.Monad.Trans.Changeset (Changes, Count (Increment), getChangeset, singleChange)++-- changeset-fused-effects+import Control.Effect.Changeset (Changeset, sendChange, sendCurrent)++fusedEffects :: (Has (Changeset Int (Changes Count)) sig m) => m Int+fusedEffects = do+  sendChange (Proxy @Int) $ singleChange Increment+  n <- sendCurrent (Proxy @(Changes Count))+  sendChange (Proxy @Int) $ singleChange Increment+  pure n++transformer :: (MonadChangeset Int (Changes Count) m) => m Int+transformer = do+  change $ singleChange Increment+  n <- current+  change $ singleChange Increment+  pure n++main :: IO ()+main =+  defaultMain+    $ testCase+      "fused-effects"+    $ let+       in getChangeset fusedEffects (0 :: Int) @?= getChangeset transformer (0 :: Int)