这篇文章从某种意义上来说是我之前的一篇。HTNW在他们的回答中定义了数据类型Same
和功能allEq
。所以我认为通过定义数据类型AllDifferent
、函数allDiff
和派生的someEq
和someDiff
,我将获得一种Foldable
结构的模态正方形。
如果我的工作结果是正确的,如何恰当地表征这组数据类型和函数?
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