需要澄清混淆 Http4s 消息类型 `Response[F]` / `Request[F]`

Need clarification for confusing Http4s Message Type `Response[F]` / `Request[F]`

我很难理解为什么 RequestResponseF 中被参数化。

采用类似的东西是猫效应数据类型资源。

来自文档

https://typelevel.org/cats-effect/docs/std/resource

我们找到如下定义

object Resource {
  def make[F[_], A](acquire: F[A])(release: A => F[Unit]): Resource[F, A]

  def eval[F[_], A](fa: F[A]): Resource[F, A]
}

abstract class Resource[F, A] {
  def use[B](f: A => F[B]): F[B]
}

特别是

def use[B](f: A => F[B]): F[B]说清楚了为什么Resource在F里参数化。

鉴于文档中没有任何解释 Response[F] 的内容(请注意,我非常理解为什么 F[Response],它是我不理解的内部 F),我查看了一下代码 https://github.com/http4s/http4s/blob/main/core/src/main/scala/org/http4s/Message.scala

除非我看得不够仔细,否则我找不到任何可以证明效果类型存在的理由。

谁能解释一下里面的F参数。

https://www.haskellforall.com/2013/06/the-resource-applicative.html

类似

A Resource is an IO action which acquires some resource of type a and also returns a finalizer of type IO () that releases the resource. You can think of the a as a Handle, but it can really be anything which can be acquired or released, like a Socket or AMQP Connection.

我们能否对什么是响应及其作用有一个概念性定义,这确实需要根据特定效果类型对其进行参数化?

让我们看看 Http[F, G] 的定义,这是 http4s 的核心:

/** A kleisli with a [[Request]] input and a [[Response]] output.  This type
  * is useful for writing middleware that are polymorphic over the return
  * type F.
  *
  * @tparam F the effect type in which the [[Response]] is returned
  * @tparam G the effect type of the [[Request]] and [[Response]] bodies
  */
type Http[F[_], G[_]] = Kleisli[F, Request[G], Response[G]]

Kleisli 本质上是一个有效函数的包装器:A => F[B]:

final case class Kleisli[F[_], -A, B](run: A => F[B])

如果我们在这里开发类型 tetris,我们会看到 Http 的实际类型签名是:

Request[G] => F[Response[G]]

现在,RequestResponseG 中参数化的原因是它们可能包含主体。我们从两个定义中看到这一点:

final class Request[F[_]](
    val method: Method = Method.GET,
    val uri: Uri = Uri(path = "/"),
    val httpVersion: HttpVersion = HttpVersion.`HTTP/1.1`,
    val headers: Headers = Headers.empty,
    val body: EntityBody[F] = EmptyBody,
    val attributes: Vault = Vault.empty

final case class Response[F[_]](
    status: Status = Status.Ok,
    httpVersion: HttpVersion = HttpVersion.`HTTP/1.1`,
    headers: Headers = Headers.empty,
    body: EntityBody[F] = EmptyBody,
    attributes: Vault = Vault.empty)
    extends Message[F] {

您可以看到 F 用于 EntityBody[F],它本身是 Stream[F, Byte] 的类型别名,用于在效果 F.

针对HttpRoutes[F]的情况,两个类型参数实际上是相同的:

type HttpRoutes[F[_]] = Http[OptionT[F, *], F]

这是真的:

Request[F] => F[Option[Response[[F]]]

因此我们到处都看到 F[Response[F]] 而不是单独的类型参数体。

综上所述,F[Response[G]] 中的外部 F 用于捕获生成响应可能是有效操作这一事实。这就是为什么 F 通常是某种 IO 类型(cats-effect IOZIO[R, E, A] 等),而 request/response 中的内部 G用于模拟在给定效果中产生字节的流。