<div dir="auto"><div>In my opinion, such a class should usually have more than one parameter. In the case of Set, I think it makes more sense to use a value type than a constraint type.</div><div dir="auto"><br></div><div dir="auto"><span style="font-family:sans-serif">class e ~ Elem s => SetC e s where</span><br style="font-family:sans-serif"><span style="font-family:sans-serif"> type Elem s :: Type</span></div><div dir="auto"> type Elem (_ a) = a<br style="font-family:sans-serif"><span style="font-family:sans-serif"> singleton :: e -> s</span></div><div dir="auto"><span style="font-family:sans-serif"> elem :: e -> s -> Bool</span></div><div dir="auto"><span style="font-family:sans-serif"> union :: s -> s -> s</span></div><div dir="auto"><font face="sans-serif"> ...</font></div><div dir="auto"><span style="font-family:sans-serif"><br></span></div><div dir="auto"><font face="sans-serif">instance Ord a => SetC a (S.Set a) where</font></div><div dir="auto"><font face="sans-serif"> singleton = S.singleton</font></div><div dir="auto"><font face="sans-serif"> ...</font></div><div dir="auto"><font face="sans-serif">instance a ~ Int => SetC a IntSet where</font></div><div dir="auto"><font face="sans-serif"> type Elem IntSet = Int</font></div><div dir="auto"><font face="sans-serif"> ...</font></div><div dir="auto"><font face="sans-serif"><br></font></div><div dir="auto"><font face="sans-serif">For maps, you can do something similar:</font></div><div dir="auto"><font face="sans-serif"><br></font></div><div dir="auto"><font face="sans-serif">class k ~ Key m => MapC k m where</font></div><div dir="auto"><font face="sans-serif"> type Key m :: Type</font></div><div dir="auto"><font face="sans-serif"> type Key (_ k) = k</font></div><div dir="auto"><font face="sans-serif"> lookup :: k -> m a -> Maybe a</font></div><div dir="auto"><font face="sans-serif"> ...</font></div><div dir="auto"><font face="sans-serif"><br></font></div><div dir="auto"><font face="sans-serif">instance Ord k => MapC k (M.Map k) where</font></div><div dir="auto"><font face="sans-serif"> lookup = M.lookup</font></div><div dir="auto"><font face="sans-serif"> ....</font></div><div dir="auto"><font face="sans-serif"><br></font></div><div dir="auto">instance k ~ Int => MapC k IM.IntMap where</div><div dir="auto"> type Key IntMap = Int</div><div dir="auto"> lookup = IM.lookup</div><div dir="auto"><br></div><div dir="auto">If you like, you can add some constraints, like Traversable m. If you want to use MFoldable for sets, you can use its Element type family instead of Elem.</div><div dir="auto"><br><div class="gmail_quote" dir="auto"><div dir="ltr">On Fri, Sep 7, 2018, 11:25 AM Johannes Waldmann <<a href="mailto:johannes.waldmann@htwk-leipzig.de">johannes.waldmann@htwk-leipzig.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Dear Cafe,<br>
<br>
<br>
we have Data.Set, Data.IntSet, Data.HashSet,<br>
and they all have similar API, where the only difference<br>
is the constraint on the elements. (Same thing for maps.)<br>
<br>
Can we unify this as follows:<br>
<br>
{-# language ConstraintKinds, TypeFamilies #-}<br>
class SetC s where<br>
type Con s :: * -> Constraint<br>
singleton :: (Con s a) => a -> s a<br>
foldMap :: (Con s a, Monoid m) => (a -> m) -> s a -> m<br>
...<br>
<br>
Then for Data.Set, we write<br>
<br>
instance SetC S.Set where type Con S.Set = Ord ; ...<br>
<br>
It seems to work, and it allows me to write polymorphic code,<br>
and switch implementations from the top.<br>
Full source:<br>
<a href="https://gitlab.imn.htwk-leipzig.de/waldmann/pure-matchbox/tree/master/src/Data/Set" rel="noreferrer noreferrer" target="_blank">https://gitlab.imn.htwk-leipzig.de/waldmann/pure-matchbox/tree/master/src/Data/Set</a><br>
Example use case (switch implementation):<br>
<a href="https://gitlab.imn.htwk-leipzig.de/waldmann/pure-matchbox/blob/master/src/Matchbox/Tiling/Working.hs#L48" rel="noreferrer noreferrer" target="_blank">https://gitlab.imn.htwk-leipzig.de/waldmann/pure-matchbox/blob/master/src/Matchbox/Tiling/Working.hs#L48</a><br>
<br>
<br>
<br>
Still, there are some clumsy corners in this code, perhaps you can help:<br>
<br>
<br>
* for instance SetC HashSet, there are two constraints. I want to write<br>
<br>
type Con HashSet = \ e -> (Hashable e, Eq, e)<br>
<br>
but this does not work (there is no "type lambda"?)<br>
<br>
<br>
* for maps, I want to write<br>
<br>
class (forall k . Foldable m k) => MapC m<br>
<br>
but this seems impossible now (This is would work<br>
with -XQuantifiedConstraints ?)<br>
<br>
<br>
* in some other code using the same idea (the class exports the<br>
constraint), I had an instance where the constraint was empty.<br>
<br>
Again, I cannot write type Con Foo = \ s -> ()<br>
<br>
<br>
- J.W.<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.</blockquote></div></div></div>