Skip to content

Conversation

@meooow25
Copy link
Contributor

For #732

To avoid the naming conflict, just like Map's link2.
This is similar to the existing API for Map.

filterA :: Applicative f => (a -> f Bool) -> Set a -> f (Set a)
filterA f = go
where
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to start with this? I think it should help a little in general and a lot for some functors.

go t@(Bin 1 x _ _) = finish <$> f x
  where
    finish False = Tip
    finish True = t

The extra sharing here makes me think we probably want to share any unchanged subtrees. We don't even need to use pointer equality for that, though doing so might turn out to be fastest.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, updated to use ptrEq as we do in filter. I think it makes sense to keep them consistent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I still think you should consider special-casing a size of 1. We inherently know its subtrees don't change, plus we avoid the liftA3.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point about the liftA3, done.

I expect that this is also a little faster because of #1069, but whether we should do this everywhere is still an open question.

@treeowl
Copy link
Contributor

treeowl commented Dec 27, 2025

I don't remember who wrote the current code for alterF. It has an idea that we probably don't want here, but there should be a note about why. In particular, alterF shares the insertion and deletion structures throughout a functor that turns out to be a container. If I'm thinking about it right, we don't want anything like that here because the space leak potential is very high. There's an explosion in possible results, which all have to be kept around even if the container is consumed incrementally.

@meooow25
Copy link
Contributor Author

I'm not sure I see how the alterF idea could be applied for filterA. alterF tries to eagerly calculate the set we would get if the function happens to change it. This is feasible because there is only one such set. For filterA, each element can be kept or dropped, which leads to $2^n-1$ other sets if we try the same thing.

Personally I don't think the alterF implementation is a good idea because it always allocates the other set, even if it turns out to be not the result. But this is a little off the current topic.

@treeowl
Copy link
Contributor

treeowl commented Dec 28, 2025

Good point. We probably should discuss the alterF implementation elsewhere. It's clever in some contexts, but problematic in others.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants