Reputation: 457
I have a library project, with quite few specialized monomorphic containers (mostly sets and also some map-like). They all share the basic Set functioanality (empty, singleton, insert, union etc), but also have additional value-specific functions. Some of them are just wrappers around Data.Set, but others need more efficient implementations (like finite bitset). I have 2 questions:
What are the pros and cons of suffixing every such function (emptyT, singletonU)? Would it make a good general practice to suffix all monomorphic container functions to easier differentiate between them, and the polymorphic ones?
Here is some sample code.
import qualified Data.Set as S
data T = ...
newtype TSet = TSet { unpack :: S.Set T }
emptyT = TSet S.empty
singletonT = TSet . S.singleton
Is this the right way to wrap around polymorphic containers? Is there any more clever way to "inherit" functionality? I thought about creating a custom Set typeclass, but after reading some posts here I see it would only overcomplicate things..
Upvotes: 1
Views: 86
Reputation: 116139
I'd recommend you use a module for each monomorphic specialization.
Consider modules names Data.Set.Specialized.Int
, Data.Set.Specialized.Char
etc.
Reuse, as much as possible, the same names used in Data.Set
, without any suffix.
Make your modules be used with import qualified
, as Data.Set
.
Advantages:
if one wants to change their Data.Set
code to the specialized variant, this be dome simply by changing the types, from e.g.
import qualified Data.Set as S
foo :: S.Set Int -> String
to
import qualified Data.Set.Specialized.Int as SI
foo :: SI.Set -> String
without touching the code.
A typeclass is also a possibility, but one needs to be careful to choose the common operations among all variants. Also, if I understand correctly, you still want to allow some sets to have special operations which are not available for other sets. These much be outside the hypothetical type class, of course.
For question 2: if the wrapping is a newtype
around Data.Set
, you should consider safe coercions.
module Data.Set.Specialized.Int where
import qualified Data.Set as S
import Data.Coerce
newtype Set = Set { unSet :: S.Set Int }
union :: Set -> Set -> Set
union = coerce S.union
Upvotes: 1