(新?)可折叠模态运算符
(New?) Modal Operators for Foldable
post 在某种意义上遵循 . HTNW, , 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 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
我会说你的函数形成了一个对立方,因为它们表达了量化——更具体地说,是对可折叠容器中成对元素的某个谓词的量化[注 1]。从这个角度来看,涉及模态算子的对立方块反映了如何将模态理解为局部量化的形式。我没有看到从您的功能到传统模式更直接的 link。
从更广泛的角度来看,我所知道的在 Haskell 中表达模态的大多数方法在理论层面上都是由 Curry-Howard 同构介导的——参见 中的一些对此的参考。我从来没有听说过有人试图从模态的角度来思考数据结构的属性。但是,我认为这并非不可能以某种方式有意义 [注 2]。
注1:我说"pairs of elements"是从将关系视为成对集合的角度出发的。具体来说,我正在考虑 allEq
...
的赛外实施
allEq :: (Foldable f, Eq a) => f a -> Bool
allEq xs = all (uncurry (==)) (liftA2 (,) xs' xs')
where
xs' = toList xs
... 其中我们检查某个 属性,即 uncurry (==)
是否适用于 xs
.
的所有元素对
注 2: 首先,可能世界语义可以使用图来处理,如 this demo.
中生动说明的那样
post 在某种意义上遵循 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 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
我会说你的函数形成了一个对立方,因为它们表达了量化——更具体地说,是对可折叠容器中成对元素的某个谓词的量化[注 1]。从这个角度来看,涉及模态算子的对立方块反映了如何将模态理解为局部量化的形式。我没有看到从您的功能到传统模式更直接的 link。
从更广泛的角度来看,我所知道的在 Haskell 中表达模态的大多数方法在理论层面上都是由 Curry-Howard 同构介导的——参见
注1:我说"pairs of elements"是从将关系视为成对集合的角度出发的。具体来说,我正在考虑 allEq
...
allEq :: (Foldable f, Eq a) => f a -> Bool
allEq xs = all (uncurry (==)) (liftA2 (,) xs' xs')
where
xs' = toList xs
... 其中我们检查某个 属性,即 uncurry (==)
是否适用于 xs
.
注 2: 首先,可能世界语义可以使用图来处理,如 this demo.
中生动说明的那样