I want a Bag container which hides its 'real' order from its clients.
It also must be fully polymorphic, that is shouldn't require any constraints over its element type.
I found at least three implementations of bags: Bag
module from ghc
package, Data.Bag
from bag
and Math.Combinatorics.Multiset
from multiset-comb
.
However, they all have toList
and fold*
operations which expose the internal order of elements which may depend on implementation details or the order of bag construction.
toList
is impossible, at least with type Bag a -> [a]
. However, folding does not always expose the order.
For example, fold (+) 0
does not expose.
The question is, how should I design the folding interface? Is there a necessary and sufficient condition for safety of the a -> a -> a
folding function? As fmap
does not expose the order, is there a loss of genericity from folding with a -> b -> b
?
I'm thinking of commutative monoids - they seem sufficient, but I'm not sure if associativity and identity element are necessary.
reduce :: Monoid m => (a -> m) -> Bag a -> m
would do the trick, with the idea is that the only thing that the caller ofreduce
can see is individualBag
elements in isolation. The problem is that the caller can also implement theMonoid
instance, and thus is able to observe some concrete order of the elements. I'm afraid it's impossible to have an operation that enumerates elements and yet forbid clients from coupling themselves to the contingent order in which it produces the elements. The only solution may be to produce elements in a well-defined order. – PorousCommutativeMonoid m => (a -> m) -> Bag a -> m
is a good idea as its type passes enough information to the caller to avoid ill-behaved functions and design a library of well-defined functions. I don't want to restrain callers from hurting themselves if they want to, I just want to avoid unintended bugs. For example, if I use only stock commutative monoids to reduce I get a pretty strong guarantee that my code doesn't depend on the order. I asked the question because I encountered a list monad which is not quite a monad as it violates laws by permuting. – Savino