VinylRecords / Vinyl

Extensible Records for Haskell. Pull requests welcome! Come visit us on #vinyl on freenode.
http://hackage.haskell.org/package/vinyl
MIT License
262 stars 48 forks source link

Food for thought about Dict and constraints #75

Open andrewthad opened 9 years ago

andrewthad commented 9 years ago

I occasionally find that I need a record of constraints without actually having values. The Dict definition in vinyl requires a value, I started by passing undefined (eww...), but I have now settled on an alternative MyDict formulation that I am using. The relevant parts of my code look like this:

data MyDict (c :: * -> Constraint) a where
  MyDict :: c a => MyDict c a

recFromProxy :: forall f rs. RecApplicative rs => Proxy (Rec f rs) -> Rec (Proxy :. f) rs
recFromProxy _ = rpure (Compose Proxy)

otherReifyConstraint :: RecAll f rs c => proxy c -> Rec (Proxy :. f) rs -> Rec (MyDict c :. f) rs
otherReifyConstraint prx rec =
  case rec of
    RNil -> RNil
    (Compose x :& xs) -> Compose (toDict x) :& otherReifyConstraint prx xs
  where toDict :: c a => Proxy a -> MyDict c a
        toDict _ = MyDict

This is particularly more useful when you're dealing with the Typeable constraint or when you're just trying to extract methods from a typeclass (I know that sounds weird but I have a reasonable use case for it). At any rate, I was wondering if there was a way that Dict and reifyConstraint could somehow be built on top of the alternatives I have written (as mine require strictly less information) and then both possibilities could be offered from the same core code. Just food for thought.

acowley commented 9 years ago

I do some things with reifying type class dictionaries in Frames, too. See here for example. I think I have a couple variations of this in various places, but I'm not sure what the maximally useful shape is yet.

schernichkin commented 9 years ago

I've faced similar problem when I needed to extract attribute type information, but not the attribute value itself. I've also created recordProxy :: forall f . Rec (Proxy :. f) rs function (but my version is based on type classes, your seems to be more elegant) and reifyProxyConstraint :: RecAll f rs c => proxy c -> Rec (Proxy :. f) rs -> Rec (ProxyDict c :. f) rs for ProxyDict which I defined as data ProxyDict c a where ProxyDict :: c a => Proxy a -> ProxyDict c a. My code is here.

Your approach seems to be more generic and it definitely should be explored, because current version of reifyConstraint not usable with proxies.