I would like to understand the differences between the following two definitions of a Collection type class.
With multiparameter typeclasses and functional dependencies (taken from here);
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}
class Eq e => Collection c e | c -> e where
insert :: c -> e -> c
member :: c -> e -> Bool
instance Eq a => Collection [a] a where
insert = flip (:)
member = flip elem
With only a single type parameter;
class Collection c where
insert :: Eq e => c e -> e -> c e
member :: Eq e => c e -> e -> Bool
instance Collection [] where
insert = flip (:)
member = flip elem
Both seem to compile and work ok. Are there any practical differences between the two, or any reason to favour one approach over the other?
A simple example where the Fundep version still works, but not the single-parameter one, is a Set
container:
import qualified Data.Set as Set
instance (Ord e) => Collection (Set.Set e) e where
insert = Set.insert
member = flip Set.member
An instance to the other class doesn't work because you need an Ord
constraint. Now, you could change the definitions to
class Collection c where
insert :: Ord e => c e -> e -> c e
member :: Ord e => c e -> e -> Bool
But for simpler containers like lists that would merely be a nuisance, you'd like to also store non-ord types there. For Hashmaps you need yet another constraint. It's no good making those global and required for any collection.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With