Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add intersections function #41

Open
milesfrain opened this issue Dec 23, 2020 · 6 comments
Open

Add intersections function #41

milesfrain opened this issue Dec 23, 2020 · 6 comments
Labels
type: enhancement A new feature or addition.

Comments

@milesfrain
Copy link
Contributor

milesfrain commented Dec 23, 2020

We have union, unions, and intersection, but no intersections.

I've been using this locally:

intersections :: forall f a. Foldable f => Ord a => f (Set a) -> Set a
intersections sets = case List.fromFoldable sets of
  Nil -> Set.empty
  (x : xs) -> foldl intersection x xs

PR with tests and docs on the todo list.

@hdgarrood
Copy link
Contributor

The only problem with this is that the intersections of an empty list of sets really ought to be a set containing every inhabitant of a, which is not possible without an extra constraint (I think BoundedEnum is enough) but also constructing such a set is probably not something you ever want to do anyway. I think this should have a Foldable1 constraint if we are going to include it here.

@milesfrain
Copy link
Contributor Author

milesfrain commented Dec 24, 2020

We can start with a Foldable1 intersections, but I suspect there will be requests for a version that allows an empty list of sets (and returns a more pragmatic empty set in that case). I think many algorithms end up being cleaner with this allowance.

For example, I tried rewriting this Venn diagram code with non-empty intersections, and it ended up turning into a huge mess. Here's the original:
https://try.ps.ai/?gist=6a0fff8192710ab520e9cc1039ddd223
Maybe someone with more FP experience can see a better way to rewrite this with Foldable1.

The simplest fix I found for the above is to simply recreate the desired library function locally:

my_intersections :: forall f a. Foldable f => Ord a => f (Set a) -> Set a
my_intersections sets = case List.fromFoldable sets of
  Nil -> Set.empty
  (x : xs) -> intersections $ NEL.cons' x xs

Also, I was hoping that this would be a valid way to write the Foldable1 version:

intersections :: forall f a. Foldable1 f => Ord a => f (Set a) -> Set a
intersections = foldl1 intersection

But it will not compile because foldl1 is not a member of Foldable1. This is surprising because foldl is a member Foldable. Should Foldable1 be changed to include equivalents of all the Foldable members (foldr, foldl, foldMap)? If not, how would you write this function?

@kl0tl
Copy link
Member

kl0tl commented Dec 24, 2020

Foldable1 has a foldl1 method since purescript/purescript-foldable-traversable#121.

@hdgarrood
Copy link
Contributor

The reason I don’t want to have an intersections function which says that the intersection of an empty list of sets is empty is that properties like intersections (xs <> ys) = intersect (intersections xs) (intersections ys) are the kind of thing you’ll make use of without realising you’re doing so, especially since unions already satisfies a similar property. I’m not currently convinced that lots of algorithms end up being cleaner with the Foldable version of intersections, but I’m open to being persuaded. I don’t see it as too much of a problem if people do end up writing my_intersections functions downstream, because at least they will have had to consciously consider the empty list input that way.

@hdgarrood
Copy link
Contributor

I have to admit I haven’t been able to work out what your vennCell is trying to do.

@milesfrain
Copy link
Contributor Author

I don’t see it as too much of a problem if people do end up writing my_intersections functions downstream

That sounds good for now. Can always add it to the library later if there's more demand or evidence that it simplifies things.


Foldable1 has a foldl1 method since purescript/purescript-foldable-traversable#121.

Thanks. I've been relying too much on Pursuit / Starsuit to answer these questions.


I have to admit I haven’t been able to work out what your vennCell is trying to do.

It finds the contents of a "cell" in a venn diagram if provided with which sets to consider ("keep") and exclude ("toss"). For example, given these labeled sets:

"A" [1, 2, 4, 5]
"B" [1, 3, 4, 7]
"C" [1, 2, 3, 6]

which represents this diagram:

If vennCell is given {keep: [A, B], toss: [C]}, it will find [4] and apply the appropriate "A B" label.

Full try-purescript output for that basic input is:

-----
A B C
-----
1

-----
B C
-----
3

-----
A C
-----
2

-----
C
-----
6

-----
A B
-----
4

-----
B
-----
7

-----
A
-----
5

The results are more interesting if each cell contains more than one element, such as in purescript/purescript-lists#183

@JordanMartinez JordanMartinez added the type: enhancement A new feature or addition. label Dec 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A new feature or addition.
Projects
None yet
Development

No branches or pull requests

4 participants