真正无序的可折叠包

时间:2012-09-05 12:32:24

标签: haskell types bag commutativity

我想要一个袋子容器,它隐藏了客户的“真实”订单。

它也必须是完全多态的,不应该对其元素类型有任何约束。

我找到了至少三个行李的实现:来自Bag包的ghc模块,来自Data.Bag的{​​{1}}和来自bag的{​​{1}}。

但是,它们都有Math.Combinatorics.Multisetmultiset-comb个操作,这些操作会暴露元素的内部顺序,这可能取决于实现细节或包构造的顺序。

toList是不可能的,至少是fold*类型。但是,折叠并不总是暴露订单。

例如,toList不会公开。

问题是,我该如何设计折叠界面? Bag a -> [a]折叠功能的安全是否有必要且充分的条件?由于fold (+) 0没有公开订单,因此使用a -> a -> a折叠是否会失去通用性?

我正在考虑可交换的幺半群 - 它们似乎已经足够了,但我不确定是否有必要使用关联性和身份元素。

1 个答案:

答案 0 :(得分:6)

如果您的行李可能是空的,则可能需要身份证明 - 在这种情况下您必须返回某些内容,并且如果您希望您的折叠是同态的(这样折叠某些行李的结果与折叠行李相同)通过组合袋子制成的袋子,这是一种非常自然的特性,它必须是一个标识元素。

同样,相关性是一个好主意。假设我有类似的操作:

data T a = Zero | One a | Two (T a) (T a)
  deriving (Eq, Ord, Show)

(+-+) :: Ord a => T a -> T a -> T a
Zero +-+ x = x
x +-+ Zero = x
a +-+ b = Two (min a b) (max a b)

显然(+-+)是可交换的并且具有同一性,但是不具有关联性。假设我然后将一个包作为列表实现:

newtype Bag a = Bag [a]

-- pre-condition: f is commutative and z is an identity for it
foldBag :: (a -> a -> a) -> a -> Bag a -> a
foldBag f z (Bag xs) = foldr f z xs

foldNonAssoc :: (Ord a) => Bag (T a) -> T a
foldNonAssoc = foldBag (+-+) Zero

即使我要求所述的前提条件,我仍然可以使用我的foldNonAssoc来区分Bag [One 1,One 2,One 3],它将折叠为Two (One 1) (Two (One 2) (One 3))Bag [One 3,One 2,One 1],这将折叠为Two (One 3) (Two (One 1) (One 2))(请注意,不会保留所有结构,但在长列表中,除了最后两个元素的排序之外,我将获得整个列表顺序。)

先验地,如果您将所有项目与操作组合在一起,您将拥有一个应用程序树,例如a +-+ (b +-+ (c +-+ d))。交换性可以让你做一些重新安排,但不管你做什么,c总是与d结合。因此,如果您希望它与(a +-+ c) +-+ (b +-+ d)相同,那么您也需要关联性。