newtype
wrappers for oset
I recently published oset-0.1.1.0
in order to get around some (perceived, by me) shortcomings of ordered-containers
. Mainly I was frustrated by the lack of Semigroup
and Monoid
instances.
In retrospect, I think I should have thought some more before ploughing ahead and implementing them the way I did, mainly because there are ( think) at least two valid, and obvious, possible instances of these type classes for an ordered set. Specifically:
Therefore, I’m planning to remove the existing Semigroup
and Monoid
instances and replace them with newtype
wrappers providing the desired behaviours. Here’s a sketch of what I intend to do:
#!/usr/bin/env stack | |
-- stack --resolver=lts-12.6 script | |
{-# LANGUAGE DuplicateRecordFields #-} | |
{-# LANGUAGE StandaloneDeriving #-} | |
module Main (main) where | |
import Data.List (nub) | |
data OSet a = OSet [a] | |
deriving instance Show a => Show (OSet a) | |
empty :: OSet a | |
empty = OSet [] | |
singleton :: a -> OSet a | |
singleton a = OSet [a] | |
insert :: Eq a => a -> OSet a -> OSet a | |
insert b (OSet as)= OSet (nub (as ++ [b])) | |
leftPreservingAppend :: Eq a => OSet a -> OSet a -> OSet a | |
leftPreservingAppend (OSet as) (OSet bs) = OSet (nub (as ++ bs)) | |
rightPreservingAppend :: Eq a => OSet a -> OSet a -> OSet a | |
rightPreservingAppend (OSet as) (OSet bs) = OSet (reverse $ nub (reverse bs ++ reverse as)) | |
toList :: OSet a -> [a] | |
toList (OSet as) = as | |
newtype LeftPreservingOSet a = LeftPreservingOSet { getOSet :: OSet a } | |
instance Eq a => Semigroup (LeftPreservingOSet a) where | |
(LeftPreservingOSet as) <> (LeftPreservingOSet bs) = LeftPreservingOSet (leftPreservingAppend as bs) | |
instance Eq a => Monoid (LeftPreservingOSet a) where | |
mempty = LeftPreservingOSet empty | |
deriving instance Show a => Show (LeftPreservingOSet a) | |
newtype RightPreservingOSet a = RightPreservingOSet { getOSet :: OSet a } | |
instance Eq a => Semigroup (RightPreservingOSet a) where | |
(RightPreservingOSet as) <> (RightPreservingOSet bs) = RightPreservingOSet (rightPreservingAppend as bs) | |
instance Eq a => Monoid (RightPreservingOSet a) where | |
mempty = RightPreservingOSet empty | |
deriving instance Show a => Show (RightPreservingOSet a) | |
main :: IO () | |
main = do | |
print $ (getOSet :: LeftPreservingOSet Int -> OSet Int) | |
(LeftPreservingOSet (singleton 5) | |
<> LeftPreservingOSet (singleton 3) | |
<> LeftPreservingOSet (singleton 2) | |
<> LeftPreservingOSet (singleton 5)) | |
print $ (getOSet :: RightPreservingOSet Int -> OSet Int) | |
(RightPreservingOSet (singleton 5) | |
<> RightPreservingOSet (singleton 3) | |
<> RightPreservingOSet (singleton 2) | |
<> RightPreservingOSet (singleton 5)) |
leftPreservingAppend
and rightPreservingAppend
are not the real implementations but are provided for illustrative purposes only.
Content © 2025 Richard Cook. All rights reserved.