-
Notifications
You must be signed in to change notification settings - Fork 33
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
SuspenseStore refactor to allow caching of any HasBackend instance members #35
base: main
Are you sure you want to change the base?
Conversation
|
||
class IsSymbol s <= HasBackend k v (s :: Symbol) | k -> s, k -> v where | ||
fromKey :: k -> String | ||
backend :: k -> Aff v |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementing HasBackend
and calling the getters above is the external API. The classes and types below should contain the unsafe bits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this will do what you want it to: with this code, I think I can define instances
HasBackend String Int "1"
HasBackend Int Int "1"
since we are effectively only saying that there can only be one HasBackend instance for each key type k
; we aren't preventing you from defining two different instances with different k
types but the same s
type. A functional dependency s -> k
would prevent you from doing this, but that probably isn't workable because you'll fall foul of orphan instance restrictions there - since in this case s
determines everything, then the instance can only be defined in the same module as the HasBackend class. Normally you'd also be able to define the instance in the same module as the type s
, but in this case s
is built in to the compiler so you can't put it there. See https://liamgoodacre.github.io/purescript/type/class/instance/orphan/functional/dependencies/2017/01/22/purescript-orphan-instance-detection.html for more information on how functional dependencies affect orphan instance checking.
I think you'd ideally need something like Haskell's Data.Typeable to do this safely, but PureScript doesn't have that. I'm not sure there's a good way of doing this without Data.Typeable, unfortunately.
1316f9f
to
cb14a90
Compare
mkStorable :: forall k v s. HasBackend k v s => k -> StoreKey | ||
mkStorable k = StoreKey \f -> f k | ||
|
||
class Storable k where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the type class doing much for us here? In general I think defining a type class and not exporting it is a bit suspect; would normal functions work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same goes for HasOpaque
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, you're right, thanks!
|
||
class IsSymbol s <= HasBackend k v (s :: Symbol) | k -> s, k -> v where | ||
fromKey :: k -> String | ||
backend :: k -> Aff v |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this will do what you want it to: with this code, I think I can define instances
HasBackend String Int "1"
HasBackend Int Int "1"
since we are effectively only saying that there can only be one HasBackend instance for each key type k
; we aren't preventing you from defining two different instances with different k
types but the same s
type. A functional dependency s -> k
would prevent you from doing this, but that probably isn't workable because you'll fall foul of orphan instance restrictions there - since in this case s
determines everything, then the instance can only be defined in the same module as the HasBackend class. Normally you'd also be able to define the instance in the same module as the type s
, but in this case s
is built in to the compiler so you can't put it there. See https://liamgoodacre.github.io/purescript/type/class/instance/orphan/functional/dependencies/2017/01/22/purescript-orphan-instance-detection.html for more information on how functional dependencies affect orphan instance checking.
I think you'd ideally need something like Haskell's Data.Typeable to do this safely, but PureScript doesn't have that. I'm not sure there's a good way of doing this without Data.Typeable, unfortunately.
The suspense on this one is killing me! |
@i-am-the-slime tbh I'm not sure when I'll get to this. My new day job isn't using PS and I'm a bit burnt out on the after hours programming. Maybe someday inspiration will strike, but in the meantime I'll do my best to review and merge any work others want to contribute to this. |
@spicydonuts |
The old store required the key and value types of the cache to be defined at cache creation. This refactor is to allow any type implementing
HasBackend
to be stored in the cache in a (hopefully) type-safe way.The main bits I'd like feedback on:
HasBackend
class behave correctly, i.e. do the functional dependencies correctly prevent invalid instances?k
, can be used in multiple instances with a differents
orv
s
values across different choices forv
.. does that make sense?s
needs to be unique for each choice ofv
HasBackend
implementations are carried into the cache using a few internal classes,ToKey
,ToAffUnsafe
, andHasOpaque
, usingStorable
-- do these make sense?