Are you referring to Symbol in class IsSymbol (sym :: Symbol)? If so, sym is a type variable, and Symbol is the kind of that type variable. The only valid arguments to this type class are things that are of kind Symbol, which are type level strings.
This class is âmagicâ in that it is automatically solved by the compiler, so yes, all symbols effectively have an instance for IsSymbol by virtue of the compiler being able to generate the dictionary on the fly. A function doesnât work because there is nothing for the compiler to solve. You would be unable to abstract over it like what inj is doing.
@milesfrain I think that in theory you could have an implication between these constraints (Cons => IsSymbol) which you are asking for - a working approximation could be:
class (Cons l a t r, IsSymbol l) â Kons l a t r
x ⡠â l a t r. Kons l a t r â SProxy l â a â Variant r
x = inj
Cons could imply IsSymbol⌠but they are in some sens âunrelatedâ because Cons doesnât use reflectSymbol or share any âlawsâ with IsSymbol so it probably wonât happen
Another part of the reason why Cons and IsSymbol are not related is to ensure that Cons has no data (itâs purely a type-level guarantee, with unsafe foreign code supporting function implementations), while IsSymbol has to include the data for reflectSymbol in its instance, as mentioned above. Of course they are most commonly used together.
p.s. Donât forget instance kons :: (Cons l a t r, IsSymbol l) => Kons l a t r
Iâm now looking at insert and curious why Lacks is needed in addition to Cons.
insert :: forall r1 r2 l a. IsSymbol l => Lacks l r1 => Cons l a r1 r2 => SProxy l -> a -> Record r1 -> Record r2
Does Cons l a r1 r2 mean that r1 already âLacksâ l? Or does the Cons constraint alone allow for duplicate labels in r2 if r1 already contains label l?