Hi Thomas,
(sorry for the delay - I think the slack channel may receive quicker replies!)
Thanks for the very interesting question!
I would formalize those requirements as follows:
First, lets define a type for "subsets of X"
```
-- | Subsets a X is a Set (Set a) where each set is a subset of X
{-@ type Subsets a X = S.Set {v:S.Set a | S.isSubsetOf v X} @-}
```
Next, we can use your idea to build a "struct" as follows:
```
{-@ data Topology a = T
{ unX :: S.Set a
, unT :: {t: Subsets a unX | (S.member S.empty t) && (S.member unX t) }
, pfUn :: x1:{_| S.member x1 unT} -> x2:{_| S.member x2 unT} ->
{v:() | S.member (S.union x1 x2) unT}
, pfIn :: x1:{_| S.member x1 unT} -> x2:{_| S.member x2 unT} ->
{v:() | S.member (S.intersection x1 x2) unT}
}
@-}
```
Note that the requirements (1) and (2) are specified by the requirement on `unT`
For (3) and (4) I'd go with the "propositions as types" approach so the properties are:
3. The union of any collection of elements of T is also in T .
4. The intersection of any finite collection of elements of T is also in T .
Which I am rewriting (after shrinking to "pairwise" which should generalize
to any finite collection at least?) to
- forall X1, X2 in T. (union X1 X2) in T
- forall X1, X2 in T, (inter X1 X2) in T
which in turn become the function signatures for the `pfUn` and `pfIn`.
Does that help? Do let me know!
Best!
- Ranjit.