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 versions of FunctorK and ApplyK for bi- and tri-functors, with macro derivation #261

Open
nigredo-tori opened this issue Jul 26, 2021 · 2 comments
Labels
enhancement New feature or request

Comments

@nigredo-tori
Copy link
Contributor

nigredo-tori commented Jul 26, 2021

Motivation: I'm having to deal with Tapir, using it to generate client and service implementations for some APIs. I end up with values like these:

// Pure specification for an endpoint, used by the client and the server
val fooEndpoint: Endpoint[(AuthToken, FooInput), ApiError, FooOutput, Any]
// Complementary server-side implementation, without authentication.
val fooImpl: (AuthedClient, FooInput) => IO[Either[ApiError, FooOutput]]
// Endpoint + implementation
val fooServerEndpoint: ServerEndpoint[(AuthToken, FooInput), ApiError, FooOutput, Any, IO]

// Authentication, common for all endpoints
val authenticate: AuthToken => IO[Either[ApiError, AuthedClient]]

If you squint hard enough (and if you have enough endpoints to generalize), you can see that the three foo* values belong in three variants of the same shape that describes the API as a whole:

trait Api[F[_, _]] {
  def foo: F[FooInput, FooOutput]
  // more endpoints here
}

type Endpoint0[A, B] = Endpoint[(AuthToken, A), ApiError, B, Any]
type PureApi = Api[Endpoint0]

type Impl[A, B] = (AuthedClient, A) => IO[Either[ApiError, B]]
type ImplApi = Api[Impl]

type ServerEndpoint0[F[_], A, B] = ServerEndpoint[(AuthToken, A), ApiError, B, Any, F]
type ServerApi[F[_]] = Api[ServerEndpoint0[F, *, *]]

Authentication could be factored out if only Api had a version of mapK dealing with bifunctors (bimapK?). In the same vein, combining fooEndpoints and fooImpls is pure boilerplate, and could be implemented using something similar to map2K (bimap2K?).

Similar abstractions for trifunctors might also be useful, in case error types differ between endpoints.

@joroKr21 joroKr21 added the enhancement New feature or request label Mar 27, 2022
@joroKr21
Copy link
Member

I think this would only work if we have a different form of natural transformation.
Instead of type ~>[F[_], G[_]] = arrow.FunctionK[F, G] it would have to be Function2K[F[_, _], G[_, _]] 🤔

@joroKr21
Copy link
Member

joroKr21 commented Apr 1, 2024

Now that Scala 3 support is shaping up, we can add this with polymorphic functions.
But we need to first figure out how to add versions of the existing methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants