I use vinyl to declare a number of different record types, some of which have a field called Content
with a specific type LanguageContent
. For the functions that depend on the field being present in the record, I want to have a type like:
getContent :: HasContent a => a -> LanguageContent
getContent a = a ^. rlens SContent . unAttr
(Function given for illustration only; there are many functions taking something that HasContent
and doing different things with it.)
Now I just need to declare HasContent
as a constraint. The closest I can get using Data.Vinyl.Notation
is:
getContent :: (Content ∈ fs) => Rec Attr fs -> LanguageContent
A type family can be declared but the function does not typecheck:
type family HasContent c :: Constraint
type instance HasContent (Rec Attr rs) = Content ∈ rs
getContent :: HasContent a => a -> LanguageContent
getContent a = a ^. rlens SContent . unAttr
Could not deduce (a ~ Rec Attr rs0)
from the context (HasContent a)
I can make a constraint with two parameters which works but isn't ideal (rs
is a parameter that I have to repeat everywhere):
type HasContent c rs = (c ~ Rec Attr rs, Content ∈ rs)
Without the extra parameter (see answer by @ChristianConkle), I just get:
type HasContent c = (c ~ Rec Attr rs, Content ∈ rs)
Not in scope: type variable ‘rs’
How do I declare a constraint which only holds for such Rec Attr fs
that Content ∈ fs
?