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

Proposal: unique and option-alike combinators #518

Open
satorg opened this issue Oct 1, 2024 · 5 comments
Open

Proposal: unique and option-alike combinators #518

satorg opened this issue Oct 1, 2024 · 5 comments

Comments

@satorg
Copy link

satorg commented Oct 1, 2024

Inspired by Doobie's unique and option queries:

https://github.com/typelevel/doobie/blob/1ad3ad5e195d89becbd4097677f738a0b10aa5df/modules/core/src/main/scala/doobie/util/query.scala#L127-L139

In fact, those two are pretty common use cases: after receiving a collection of items from somewhere, we may want to make sure that there's either exactly 1 or at most 1 items received.

To make them generally available, we could consider adding two combinators to FNested2SyntaxOps:

final class FNested2SyntaxOps[F[_], G[_], A](private val fga: F[G[A]]) extends AnyVal {
  ...
  def uniqueOrRaise[E](e: E)(implicit F: MonadError[F, E], G: Foldable[G]): F[A] = ???
  def optionOrRaise[E](e: E)(implicit F: MonadError[F, E], G: Foldable[G]): F[Option[A]] = ???
}

The proposed names may not be perfect – just got borrowed them from Doobie. However, I'm absolutely open for bikeshedding.

If such combinators make sense, I'll be glad to file a PR.

@danicheg
Copy link
Member

danicheg commented Oct 1, 2024

I like the idea of these methods, but the proposed name seems a little ambiguous and uncertain. I'm more concerned about 'unique', which in the context of SQL seems fine, but outside of that scope, it could imply that the element is distinct in some way, rather than just that the collection contains exactly one element.
I think 'sole' might be a better choice here. So, what do you think about soleOrRaise and soleOrEmptyOrRaise? The latter feels clunky but at least echoes the former.
Another option here is to use 'ensure', which comes from the MonadError scope: ensureSole and ensureSoleOrEmpty. These names contradict the typical presence of a boolean predicate in the contract of MonadError methods, but we implicitly encode it in the naming with 'sole' and 'soleOrEmpty'.

@benhutchison
Copy link
Member

I would be happy to merge a PR with these additions.

I agree with @danicheg's points re: naming. I like ensureSole and ensureSoleOrEmpty myself.

@satorg
Copy link
Author

satorg commented Oct 3, 2024

@danicheg , @benhutchison , thank you for your feedback!

Yes, I agree that we should choose better names – I picked those just to have something to start with.

Regarding the suggested ones. At first I favored the ensureSole* options. But then it appeared to me that those names might not be fully idiomatic, because the original ensure and ensureOr combinators do not modify their inputs. But the combinators we're discussing are supposed to do that. So perhaps, the sole...OrRaise names would be a better fit for them.

Btw, is the `sole` word better in this context comparing to `single`? Just wondering, because I usually see something like "single-ton" but not "sole-ton". Just out of curiosity though – I'm totally fine with the "sole" wording anyway.

@satorg
Copy link
Author

satorg commented Oct 3, 2024

Another thing that I feel it is important to think through.

Initially, I proposed the Foldable typeclass to use for the sake of generalization, which would be able to do the job for sure.

However, there's another one in Cats – UnorderedFoldable, which is a parent for Foldable. For example, UnorderedFoldable captures hash-based Sets. Therefore I feel that UnorderedFoldable could be a better bet to rely upon for the proposed functionality. Unfortunately, UnorderedFoldable looks a bit under-developed at the moment. It doesn't include methods that would allow to short-circuit calculations. For example, Foldable has foldM, etc, but there's nothing like that in UnorderedFoldable. And I wouldn't like to be forced to go through all the items just to check whether there are more than one available.

Therefore I think that perhaps it would be beneficial to give it a shot and add the missing combinators to UnorderedFoldable first, then come back to this task later once the missing functionality becomes enabled. Or do you think that Foldable is already good enough for that?

Thank you!

@benhutchison
Copy link
Member

@satorg It's clear youve given this a lot of thought. I'll back whichever choice you come to in terms of sole / single, and ensure / ..OrRaise.

Seems depending on UnorderedFoldable would be ideal. If you have the patience and energy to extend that class with foldM, then circle back and add these operators, great! If not, and just go with Foldable, it's still a net gain in my view.

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

No branches or pull requests

3 participants