I find myself running into a problem commonly, when writing larger programs in Haskell. I find myself often wanting multiple distinct types that share an internal representatio
There's another straightforward approach.
data MyGenType = Foo | Bar
op :: MyGenType -> MyGenType
op x = ...
op2 :: MyGenType -> MyGenType -> MyGenType
op2 x y = ...
newtype MySpecialType {unMySpecial :: MyGenType}
inMySpecial f = MySpecialType . f . unMySpecial
inMySpecial2 f x y = ...
somefun = ... inMySpecial op x ...
someOtherFun = ... inMySpecial2 op2 x y ...
Alternately,
newtype MySpecial a = MySpecial a
instance Functor MySpecial where...
instance Applicative MySpecial where...
somefun = ... fmap op x ...
someOtherFun = ... liftA2 op2 x y ...
I think these approaches are nicer if you want to use your general type "naked" with any frequency, and only sometimes want to tag it. If, on the other hand, you generally want to use it tagged, then the phantom type approach more directly expresses what you want.