packages feed

dep-t-advice 0.4.5.0 → 0.4.6.0

raw patch · 4 files changed

+135/−60 lines, 4 filesdep +barbiesPVP ok

version bump matches the API change (PVP)

Dependencies added: barbies

API changes (from Hackage documentation)

+ Control.Monad.Dep.Advice: instance Control.Monad.Dep.Advice.AdvisedComponent (Control.Monad.Dep.Advice.DiscriminateAdvisedComponent advised) ca e_ m cr advised => Control.Monad.Dep.Advice.AdvisedComponent 'Control.Monad.Dep.Advice.IWrapped ca e_ m cr (Data.Functor.Identity.Identity advised)
+ Control.Monad.Dep.Advice: instance Control.Monad.Dep.Advice.GullibleComponent (Control.Monad.Dep.Advice.DiscriminateGullibleComponent gullible) e e_ m gullible deceived => Control.Monad.Dep.Advice.GullibleComponent 'Control.Monad.Dep.Advice.IWrapped e e_ m (Data.Functor.Identity.Identity gullible) (Data.Functor.Identity.Identity deceived)

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for dep-t-advice
 
+## 0.4.6.0 
+
+* `adviseRecord` and `deceiveRecord` now work with records having fields wrapped in `Identity`.
+
+  This is for better compatibility with the [barbies](http://hackage.haskell.org/package/barbies) package.
 
 ## 0.4.5.0 
 
dep-t-advice.cabal view
@@ -1,7 +1,7 @@ cabal-version:       3.0
 
 name:                dep-t-advice
-version:             0.4.5.0
+version:             0.4.6.0
 synopsis:            Giving good advice to functions in a DepT environment.
 description:         Companion to the dep-t package. Easily add behaviour to functions living in a DepT environment, 
                      whatever the number of arguments they might have.
@@ -59,6 +59,8 @@   import:              common-tasty
   type:                exitcode-stdio-1.0
   main-is:             weird-advice-tests.hs
+  build-depends:       
+                       barbies            ^>= 2.0.2.0
 
 -- VERY IMPORTANT for doctests to work: https://stackoverflow.com/a/58027909/1364288
 -- http://hackage.haskell.org/package/cabal-doctest
lib/Control/Monad/Dep/Advice.hs view
@@ -117,13 +117,14 @@ import Control.Monad.Dep
 import Control.Monad.Dep.Has
 import Control.Monad.Trans.Reader (ReaderT (..), withReaderT)
+import Data.Functor.Identity
 import Data.Kind
+import Data.List.NonEmpty qualified as N
 import Data.SOP
 import Data.SOP.Dict
 import Data.SOP.NP
-import GHC.Generics qualified as G
-import Data.List.NonEmpty qualified as N
 import Data.Typeable
+import GHC.Generics qualified as G
 import GHC.TypeLits
 
 -- $setup
@@ -155,7 +156,7 @@ -- >>> import System.IO
 -- >>> import Data.IORef
 -- >>> import GHC.Generics (Generic)
--- >>> import GHC.Generics qualified 
+-- >>> import GHC.Generics qualified
 
 -- | A generic transformation of 'DepT'-effectful functions with environment
 -- @e_@ of kind @(Type -> Type) -> Type@, base monad @m@ and return type @r@,
@@ -694,7 +695,7 @@   where
   _deceiveProduct f (gullible_left G.:*: gullible_right) = _deceiveProduct @_ @e @e_ @m f gullible_left G.:*: _deceiveProduct @_ @e @e_ @m f gullible_right
 
-data RecordComponent 
+data RecordComponent
   = Terminal
   | IWrapped
   | Recurse
@@ -703,6 +704,7 @@ type family DiscriminateGullibleComponent c where
   DiscriminateGullibleComponent (a -> b) = Terminal
   DiscriminateGullibleComponent (ReaderT e m x) = Terminal
+  DiscriminateGullibleComponent (Identity _) = IWrapped
   DiscriminateGullibleComponent (I _) = IWrapped
   DiscriminateGullibleComponent _ = Recurse
 
@@ -717,8 +719,13 @@   _deceiveComponent f gullible = deceive @as @e @_ @m @r f gullible
 
 instance
-  GullibleComponent (DiscriminateGullibleComponent gullible) e e_ m gullible deceived
-  =>
+  GullibleComponent (DiscriminateGullibleComponent gullible) e e_ m gullible deceived =>
+  GullibleComponent IWrapped e e_ m (Identity gullible) (Identity deceived)
+  where
+  _deceiveComponent f (Identity gullible) = Identity (_deceiveComponent @(DiscriminateGullibleComponent gullible) @e @e_ @m f gullible)
+
+instance
+  GullibleComponent (DiscriminateGullibleComponent gullible) e e_ m gullible deceived =>
   GullibleComponent IWrapped e e_ m (I gullible) (I deceived)
   where
   _deceiveComponent f (I gullible) = I (_deceiveComponent @(DiscriminateGullibleComponent gullible) @e @e_ @m f gullible)
@@ -729,7 +736,6 @@   where
   _deceiveComponent f gullible = _deceiveRecord @e @e_ @m f gullible
 
-
 instance
   GullibleComponent (DiscriminateGullibleComponent gullible) e e_ m gullible deceived =>
   GullibleProduct e e_ m (G.S1 x (G.Rec0 gullible)) (G.S1 x (G.Rec0 deceived))
@@ -801,6 +807,7 @@ type family DiscriminateAdvisedComponent c where
   DiscriminateAdvisedComponent (a -> b) = Terminal
   DiscriminateAdvisedComponent (DepT e_ m x) = Terminal
+  DiscriminateAdvisedComponent (Identity _) = IWrapped
   DiscriminateAdvisedComponent (I _) = IWrapped
   DiscriminateAdvisedComponent _ = Recurse
 
@@ -809,13 +816,13 @@   _adviseComponent :: [(TypeRep, String)] -> (forall r. cr r => [(TypeRep, String)] -> Advice ca e_ m r) -> advised -> advised
 
 instance
-  (AdvisedComponent (DiscriminateAdvisedComponent advised) ca e_ m cr advised,
-   KnownSymbol fieldName
-   ) =>
-  AdvisedProduct ca e_ m cr (G.S1 ('G.MetaSel ('Just fieldName) su ss ds) (G.Rec0 advised))
+  ( AdvisedComponent (DiscriminateAdvisedComponent advised) ca e_ m cr advised,
+    KnownSymbol fieldName
+  ) =>
+  AdvisedProduct ca e_ m cr (G.S1 ( 'G.MetaSel ( 'Just fieldName) su ss ds) (G.Rec0 advised))
   where
-  _adviseProduct tr acc f (G.M1 (G.K1 advised)) = 
-     let acc' = acc ++ [(tr, symbolVal (Proxy @fieldName))]
+  _adviseProduct tr acc f (G.M1 (G.K1 advised)) =
+    let acc' = acc ++ [(tr, symbolVal (Proxy @fieldName))]
      in G.M1 (G.K1 (_adviseComponent @(DiscriminateAdvisedComponent advised) @ca @e_ @m @cr acc' f advised))
 
 instance
@@ -831,33 +838,39 @@   _adviseComponent acc f advised = advise @ca @e_ @m (f acc) advised
 
 instance
-  AdvisedComponent (DiscriminateAdvisedComponent advised) ca e_ m cr advised
-  =>
+  AdvisedComponent (DiscriminateAdvisedComponent advised) ca e_ m cr advised =>
+  AdvisedComponent IWrapped ca e_ m cr (Identity advised)
+  where
+  _adviseComponent acc f (Identity advised) = Identity (_adviseComponent @(DiscriminateAdvisedComponent advised) @ca @e_ @m @cr acc f advised)
+
+instance
+  AdvisedComponent (DiscriminateAdvisedComponent advised) ca e_ m cr advised =>
   AdvisedComponent IWrapped ca e_ m cr (I advised)
   where
   _adviseComponent acc f (I advised) = I (_adviseComponent @(DiscriminateAdvisedComponent advised) @ca @e_ @m @cr acc f advised)
 
 -- | Gives 'Advice' to all the functions in a record-of-functions.
 --
--- The function that builds the advice receives a list of tuples @(TypeRep, String)@ 
+-- The function that builds the advice receives a list of tuples @(TypeRep, String)@
 -- which represent the record types and fields names we have
 -- traversed until arriving at the advised function. This info can be useful for
 -- logging advices. It's a list instead of a single tuple because
 -- 'adviseRecord' works recursively.
--- 
+--
 -- __/TYPE APPLICATION REQUIRED!/__ The @ca@ constraint on function arguments
 -- and the @cr@ constraint on the result type must be supplied by means of a
 -- type application. Supply 'Top' if no constraint is required.
-adviseRecord :: forall ca cr e_ m advised. AdvisedRecord ca e_ m cr advised => 
-    -- | The advice to apply.
-    (forall r f . (cr r, Foldable f) => f (TypeRep, String) -> Advice ca e_ m r) -> 
-    -- | The record to advise recursively.
-    advised (DepT e_ m) -> 
-    -- | The advised record.
-    advised (DepT e_ m)
+adviseRecord ::
+  forall ca cr e_ m advised.
+  AdvisedRecord ca e_ m cr advised =>
+  -- | The advice to apply.
+  (forall r f. (cr r, Foldable f) => f (TypeRep, String) -> Advice ca e_ m r) ->
+  -- | The record to advise recursively.
+  advised (DepT e_ m) ->
+  -- | The advised record.
+  advised (DepT e_ m)
 adviseRecord = _adviseRecord @ca @e_ @m @cr []
 
-
 -- $records
 --
 -- 'adviseRecord' and 'deceiveRecord' are versions of 'advise' and 'deceive' that, instead of working on bare
@@ -887,18 +900,15 @@ --   env =
 --     let logger = Logger \_ -> pure ()
 --         repository =
---           adviseRecord @Top @Top mempty $ 
+--           adviseRecord @Top @Top mempty $
 --           deceiveRecord Wraps $
 --           Repository {select = \_ -> pure [], insert = \_ -> pure ()}
 --         controller =
---           adviseRecord @Top @Top mempty $ 
---           deceiveRecord Wraps $ 
+--           adviseRecord @Top @Top mempty $
+--           deceiveRecord Wraps $
 --           Controller \_ -> pure "view"
 --      in Env {logger, repository, controller}
 -- :}
---
---
-
 
 -- $sop
 -- Some useful definitions re-exported the from \"sop-core\" package.
test/weird-advice-tests.hs view
@@ -20,16 +20,17 @@ {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE ViewPatterns #-}
-{-# LANGUAGE DeriveGeneric #-}
 
 module Main (main) where
 
+import Barbies
 import Control.Monad.Dep
-import Control.Monad.Dep.Has
 import Control.Monad.Dep.Advice
+import Control.Monad.Dep.Has
 import Control.Monad.Reader
 import Control.Monad.Writer
 import Data.Coerce
+import Data.Functor.Identity
 import Data.Kind
 import Data.List (intercalate)
 import Data.SOP
@@ -43,22 +44,32 @@ -- https://stackoverflow.com/questions/53498707/cant-derive-generic-for-this-type/53499091#53499091
 -- There are indeed some higher kinded types for which GHC can currently derive Generic1 instances, but the feature is so limited it's hardly worth mentioning. This is mostly an artifact of taking the original implementation of Generic1 intended for * -> * (which already has serious limitations), turning on PolyKinds, and keeping whatever sticks, which is not much.
 type Logger :: (Type -> Type) -> Type
-newtype Logger d = Logger {log :: String -> d ()} deriving Generic
+newtype Logger d = Logger {log :: String -> d ()} deriving (Generic)
+
+instance FunctorB Logger
+
 instance Dep Logger where
-    type DefaultFieldName Logger = "logger"
+  type DefaultFieldName Logger = "logger"
 
 type Repository :: (Type -> Type) -> Type
 data Repository d = Repository
   { select :: String -> d [Int],
     insert :: [Int] -> d ()
-  } deriving Generic
+  }
+  deriving (Generic)
+
+instance FunctorB Repository
+
 instance Dep Repository where
-    type DefaultFieldName Repository = "repository"
+  type DefaultFieldName Repository = "repository"
 
 type Controller :: (Type -> Type) -> Type
-newtype Controller d = Controller {serve :: Int -> d String} deriving Generic
+newtype Controller d = Controller {serve :: Int -> d String} deriving (Generic)
+
+instance FunctorB Controller
+
 instance Dep Controller where
-    type DefaultFieldName Controller = "controller"
+  type DefaultFieldName Controller = "controller"
 
 type Env :: (Type -> Type) -> Type
 data Env m = Env
@@ -66,8 +77,11 @@     repository :: Repository m,
     controller :: Controller m
   }
+
 instance Has Logger m (Env m)
+
 instance Has Repository m (Env m)
+
 instance Has Controller m (Env m)
 
 -- dumb wrapper newtype
@@ -77,18 +91,15 @@ env =
   let logger = Logger \_ -> pure ()
       repository =
-        adviseRecord @Top @Top mempty $ 
-        deceiveRecord Wraps $
-        Repository {select = \_ -> pure [], insert = \_ -> pure ()}
+        adviseRecord @Top @Top mempty $
+          deceiveRecord Wraps $
+            Repository {select = \_ -> pure [], insert = \_ -> pure ()}
       controller =
-        adviseRecord @Top @Top mempty $ 
-        deceiveRecord Wraps $ 
-        Controller \_ -> pure "view"
+        adviseRecord @Top @Top mempty $
+          deceiveRecord Wraps $
+            Controller \_ -> pure "view"
    in Env {logger, repository, controller}
 
-
-
-
 ran :: Writer () String
 ran = runFromDep (pure env) serve 7
 
@@ -99,25 +110,42 @@   { logger :: h (Logger m),
     repository :: h (Repository m),
     controller :: h (Controller m)
-  } deriving Generic
+  }
+  deriving (Generic)
 
+instance Functor h => FunctorB (EnvHKD h)
+
+instance FunctorT EnvHKD
+
+instance TraversableT EnvHKD
+
+instance Has Logger m (EnvHKD I m)
+
+instance Has Repository m (EnvHKD I m)
+
+instance Has Controller m (EnvHKD I m)
+
+instance Has Repository m (EnvHKD Identity m)
+
+instance Has Controller m (EnvHKD Identity m)
+
 envHKD :: EnvHKD I (DepT Env (Writer ()))
 envHKD =
   let logger =
         I $ Logger \_ -> pure ()
       repository =
         I $
-          adviseRecord @Top @Top mempty $ 
-          deceiveRecord Wraps $
-          Repository {select = \_ -> pure [], insert = \_ -> pure ()}
+          adviseRecord @Top @Top mempty $
+            deceiveRecord Wraps $
+              Repository {select = \_ -> pure [], insert = \_ -> pure ()}
       controller =
         I $
-          adviseRecord @Top @Top mempty $ 
-          deceiveRecord Wraps $
-          Controller \_ -> pure "view"
+          adviseRecord @Top @Top mempty $
+            deceiveRecord Wraps $
+              Controller \_ -> pure "view"
    in adviseRecord @Top @Top mempty $ EnvHKD {logger, repository, controller}
 
-
+-- modified as a whole
 envHKD' :: EnvHKD I (DepT Env (Writer ()))
 envHKD' =
   let logger =
@@ -128,10 +156,40 @@       controller =
         I $
           Controller \_ -> pure "view"
-   in adviseRecord @Top @Top mempty $ 
-      deceiveRecord Wraps $
-      EnvHKD {logger, repository, controller}
+   in adviseRecord @Top @Top mempty $
+        deceiveRecord Wraps $
+          EnvHKD {logger, repository, controller}
 
+envHKDIdentity :: EnvHKD Identity (DepT Env (Writer ()))
+envHKDIdentity =
+  let logger =
+        Identity $ Logger \_ -> pure ()
+      repository =
+        Identity $
+          adviseRecord @Top @Top mempty $
+            deceiveRecord Wraps $
+              Repository {select = \_ -> pure [], insert = \_ -> pure ()}
+      controller =
+        Identity $
+          adviseRecord @Top @Top mempty $
+            deceiveRecord Wraps $
+              Controller \_ -> pure "view"
+   in adviseRecord @Top @Top mempty $ EnvHKD {logger, repository, controller}
+
+-- modified as a whole
+envHKDIdentity' :: EnvHKD Identity (DepT Env (Writer ()))
+envHKDIdentity' =
+  let logger =
+        Identity $ Logger \_ -> pure ()
+      repository =
+        Identity $
+          Repository {select = \_ -> pure [], insert = \_ -> pure ()}
+      controller =
+        Identity $
+          Controller \_ -> pure "view"
+   in adviseRecord @Top @Top mempty $
+        deceiveRecord Wraps $
+          EnvHKD {logger, repository, controller}
 
 --
 --