This post follows in a sense my previous one. HTNW, in their answer there, defined the data type Same
and the function allEq
. So I thought that by defining the data type AllDifferent
, the function allDiff
and the derived ones someEq
and someDiff
, I would have obtained a kind of modal square for Foldable
structures.
If the result of my work is correct, how can one appropriately characterise this set of data types and functions?
import qualified Data.Set as S
import qualified Data.Matrix as MT -- only for exemplification
-- EXAMPLES --
-- allEq $ MT.fromLists ["aaa","aaa"] -> True
-- allEq $ MT.fromLists ["aaa","daa"] -> False
-- someEq $ MT.fromLists ["abc","dea"] -> True
-- someEq $ MT.fromLists ["abc","def"] -> False
-- allDiff $ MT.fromLists ["abc","def"] -> True
-- allDiff $ MT.fromLists ["abc","dea"] -> False
-- someDiff $ MT.fromLists ["aaa","daa"] -> True
-- someDiff $ MT.fromLists ["aaa","aaa"] -> False
-- ====================== allEq ======================
-- produced by HTNW in response to my previous post.
data Same a = Vacuous | Fail | Same a
instance Eq a => Semigroup (Same a) where
Vacuous <> x = x
Fail <> _ = Fail
s@(Same l) <> Same r = if l == r then s else Fail
x <> Vacuous = x
_ <> Fail = Fail
instance Eq a => Monoid (Same a) where
mempty = Vacuous
allEq :: (Foldable f, Eq a) => f a -> Bool
allEq xs = case foldMap Same xs of
Fail -> False
_ -> True
-- ====================== allDiff ======================
data AllDifferent a = VacuousAD | FailAD | AllDifferent (S.Set a)
-- The lazy construction avoids taking the last union when it's not necessary, which can
-- save a significant amount of time when folding over large trees that are
-- pretty balanced at their roots.
instance (Eq a, Ord a) => Semigroup (AllDifferent a) where
VacuousAD <> x = x
FailAD <> _ = FailAD
AllDifferent l <> AllDifferent r = if S.disjoint l r
then AllDifferent (S.union l r)
else FailAD
x <> VacuousAD = x
_ <> FailAD = FailAD
instance (Eq a, Ord a) => Monoid (AllDifferent a) where
mempty = VacuousAD
allDiff :: (Foldable f, Eq a, Ord a) => f a -> Bool
allDiff xs = case foldMap (AllDifferent . S.singleton) xs of
FailAD -> False
_ -> True
-- ====================== someEq ======================
someEq :: (Foldable f, Eq a, Ord a) => f a -> Bool
someEq = not . allDiff
-- ====================== someDiff ======================
someDiff :: (Foldable f, Eq a) => f a -> Bool
someDiff = not . allEq