-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is Members
transitive?
#280
Comments
…ng `Sem.Reader` While wiring everything up, Polysemy became very, very unhappy. I spent some time trying to figure out what I was doing wrong, but with no luck. Eventually, I ended up removing `Sem.Reader (Backend backendEffs)` altogether in favor of just passing `Backend backendEffs` around as a parameter. I've since been running into what I think is a variation of polysemy-research/polysemy#280 (which I opened yesterday after finding an MVCE).
Actually, maybe it is possible to have |
Got it. Is there any workaround from the client-side perspective, do you know (regardless of how complex it might be)? |
The easiest workaround is to just get rid of |
The trick I had in mind didn't pan out. I tried leveraging quantified constraints, and define class (forall z. Members r z => Members es z, Members' es r) => Members es r
instance (forall z. Members r z => Members es z, Members' es r) => Members es r
type family Members' es r :: Constraint where
Members' '[] r = ()
Members' (e ': es) r = (Member e r, Members' es r) But for whatever reason, GHC still can't figure out the original example, and says that the use of |
@KingoftheHomeless that's due to this: https://gitlab.haskell.org/ghc/ghc/issues/14860, i think |
@isovector redefining it like this doesn't work either: class (forall z. Members' r z => Members' es z, Members' es r) => Members es r
instance (forall z. Members' r z => Members' es z, Members' es r) => Members es r
class Members' (es :: [k]) (r :: [k])
instance Members' '[] r
instance (Member h r, Members' t r) => Members' (h ': t) r or this: type Members = Members'
class Members' (es :: [k]) (r :: [k])
instance Members' '[] r
instance (forall z. Members' r z => Member h z, Member h r, Members' t r) => Members' (h ': t) r Then again, if type families trip up quantified constraints, then maybe the type families |
I tried to make an MVCE, and now I think my actual issue might be related to a combination of #114 and #188, not the transitivity of {-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
module Main where
import qualified Polysemy as Sem
import qualified Polysemy.Reader as Sem
import qualified Polysemy.State as Sem
type Callback effs fn a
= forall openEffs. (Sem.Members effs openEffs) =>
fn (Sem.Sem openEffs a)
type DependencyArgs a = a
type Dependency effs = Callback effs DependencyArgs Int
type FooCbArgs a = Int -> a
type FooCb effs = Callback effs FooCbArgs Int
injectedCb ::
forall depEffs effs.
( Sem.Member (Sem.Reader Int) effs
, Sem.Members depEffs (Sem.Reader String ': effs)
)
=> Dependency depEffs
-> FooCb effs
injectedCb dep x = Sem.runReader "" $ dep
foo ::
forall cbEffs depEffs effs.
( Sem.Members cbEffs effs
, Sem.Members depEffs effs
, Sem.Members depEffs cbEffs
)
=> Dependency depEffs
-> (Dependency depEffs -> FooCb cbEffs)
-> Sem.Sem effs Int
foo dep mkCb = mkCb dep 0
main :: IO ()
main = pure () and this is the error
If I should add this to #114, or open a new issue entirely, please let me know. (Sorry for the goose chase regarding |
What's the intent here? I think |
@isovector My main goal was to have callbacks that could have arbitrary effects, such that the calling functions can absorb them without knowing explicitly what they are. (It did work pretty well – albeit a bit boilerplate-heavy – until I ran into this issue.) |
In this specific case, I guess what I'm hoping for is to have callbacks that can themselves take callbacks, so to speak. |
So the issue here is that you're saying that The solution I think is to just be less clever. The constraint system is really good, and will propagate FWIW to work this out, I inlined all of the type synonyms, and then lifted out the rank-2 stuff which is necessary. The error was clear at this point that you're trying to run a reader that doesn't exist. This gives us: injectedCb ::
forall depEffs effs openEffs.
( Sem.Member (Sem.Reader Int) effs
, Sem.Members depEffs (Sem.Reader String ': effs)
, Sem.Members depEffs openEffs
, Sem.Members effs openEffs
)
=> Sem.Sem (Sem.Reader String ': openEffs) Int
-> Int
-> Sem.Sem openEffs Int
injectedCb dep x = Sem.runReader "" $ dep but now it's clear that none of those constraints are necessary, so the above simplifies down to injectedCb
:: Sem.Sem (Sem.Reader String ': openEffs) Int
-> Int
-> Sem.Sem openEffs Int
injectedCb dep x = Sem.runReader "" $ dep |
Ohhh, I think my confusion had been from interpreting the |
I guess one thing I'm still wondering about is, is there a way for Sorry if the question doesn't make sense, I'm still trying to wrap my head around all this 😃 |
Sorry for the delay --- somehow missed this. If you'd like to hide the For example, if you have a runReader "hello" $ do
raise foo
bar |
FWIW, I'd recommend using |
…ng `Sem.Reader` While wiring everything up, Polysemy became very, very unhappy. I spent some time trying to figure out what I was doing wrong, but with no luck. Eventually, I ended up removing `Sem.Reader (Backend backendEffs)` altogether in favor of just passing `Backend backendEffs` around as a parameter. I've since been running into what I think is a variation of polysemy-research/polysemy#280 (which I opened yesterday after finding an MVCE).
…ng `Sem.Reader` While wiring everything up, Polysemy became very, very unhappy. I spent some time trying to figure out what I was doing wrong, but with no luck. Eventually, I ended up removing `Sem.Reader (Backend backendEffs)` altogether in favor of just passing `Backend backendEffs` around as a parameter. I've since been running into what I think is a variation of polysemy-research/polysemy#280 (which I opened yesterday after finding an MVCE).
@isovector out of interest, why is that? |
|
Excuse my ignorance but when/why would I want to use local? It seems that it modifies the state of the Reader. Shouldnt we use something more like State for that? |
Personally I haven't used it, but I've imagined cases where I only need local, and not the full "power" of state (i.e. to be able to retain the change after a computation finishes) Things that come to mind are
(after writing all these out I guess anything that's in the The reason why it's in there in the first place I would guess is because |
Okay I think I got it with your examples, it seems useful indeed! Thanks! |
Could |
I haven't looked too much at how it's used, but my guess would be this: Another (and probably more important) thing that immediately comes to mind is that the current implementation also has runtime proof (the @KingoftheHomeless (and/or Sandy) is a much better fit to answer the question tbh |
This is a highly-simplified version of some
Members
constraints I'm working with (I think), and I guess I'm a bit confused why it can't compile.Specifically, the error is:
Intuitively, shouldn't being a member of
effs1
makeSem.Reader Int
transitively a member ofeffs
?The text was updated successfully, but these errors were encountered: