I think I can now float an amended law that is a further step in the right direction. First I will give the law, and then I will attempt to both motivate why the amended treatment is needed, and why the weakening of the initial proposal is a legitimate approach. Finally, I will discuss some remaining issues that it would be nice to examine, including some sketches of related but alternate approaches.
So, the new law:
===
for a lawful Foldable f, and
given a fresh newtype GenericSet = GenericSet Integer deriving (Eq, Ord), and mkGenericSet = GenericSet, where GenericSet is otherwise fully abstract
then
forall (g :: forall a. f a -> Maybe a), (x :: f GenericSet). maybe True (`Foldable.elem` x) (g x) === True==
You may recall that the prior formulation asked that this condition hold for all a., (x :: f a), and so required an external notion of equality. Here, we ask that it only hold at a _specified type_ -- i.e. "GenericSet".
So, in what sense was the older formulation "too strong"? Here is a minimal case.
data TBox a where
TAny :: a -> TBox a
TString :: String -> TBox String
TBox is just a box with some optional type information, and it should be able to be equipped with the obvious Foldable instance. However, we can now write a function such as
discrim :: forall a. TBox a -> Maybe a
discrim (TAny x) = Just x
discrim (TString _) = "zoinks"
This is to say that if we _know_ that TBox contains a string, we can now take _any_ string out of it. Clearly, the existence of such functions means that the obvious Foldable instance cannot satisfy the stronger law.
By contrast, the straightforward Foldable instance for TBox still satisfies the weaker law, as we only test the action on "GenericSet" -- and since we have defined GenericSet as a fresh newtype, we know that it cannot have a tag to be matched on within a GADT we have already defined. Hence, our law, though it gives a universal property, does not give this property itself "universally" _at every type a_ but rather at a "generic type". This is by analogy with the technique of using "generic points" in algebraic geometry [1] to give properties that are not "everywhere true" but instead are true "almost everywhere", with a precise meaning given to "almost" -- i.e. that the space for which they do not hold _vanishes_.
This is to say, a Foldable satisfying the proposed law will not have the property hold "at all types," but rather at "almost all types" for an analogously precise meaning of "almost". I believe that a statement of why GenericSet is indeed "generic" in some topological sense is possible, although I have not fully fleshed this out.
To my knowledge, the introduction of this sort of approach in an FP context is new, but I would welcome any references showing prior art.
Aside from dealing with GADTs in some fashion, the new approach has a few other useful features. First, by formulating things directly in terms of "Foldable.elem" we omit the need for some sort of notion of equality in the metalogic -- instead we can use the "Eq" typeclass directly. Furthermore, this happens to sidestep the "toList" problem in the initial approach -- it directly allows search of potentially infinite structures.
There are still a few things that could potentially be better.
1) The "fully internal" approach means that we are now subject to the "bias" of "||" -- that is to say that _|_ || True -> _|_, but True || _|_ -> True. So we do not fully capture the searchability of infinite structures. This may indicate that a retreat to a metalogical description of "elem" with unbiased "or" is in order.
2) While we can generically characterize a Foldable instance on some f "almost everywhere" this is at the cost of giving it _no_ characterization at the points where our generic characterization fails. It would be nice to establish some sort of relation between the generic characterization and the action at specified points. However, I am not quite sure how to present this. An alternate approach could be to specify a Foldable law for any `f` that first takes `f` (which may be a GADT) to a related type `f1` (which must be an ordinary ADT) that squashes or omits dictionaries and equality constraints, and likewise takes the Foldable instance to a related instance on f1, and then provides a condition on f1. So rather that retreating from universal to generic properties, we instead take hold of the machinery of logical relations directly to establish a law. I would be interested in being pointed to related work along these lines as well.
3) An additional drawback of the "Generic Point" approach as given is that we chose to derive only two particular typeclasses -- Eq and Ord. An alternate approach would be to quantify over all a, but then give the property in terms of say "newtype Generify a = Generify a deriving (...)" which derives all classes on "a" that do not feature "a" in a positive position. Doing this would also mean a retreat from a fully internal notion of equality, of course...
Anyway, this is clearly still work in progress, but I would appreciate any feedback on the direction this is going, or references that may seem useful.
Cheers,
Gershom