【问题标题】:Kleisli flatMap stange type parameter subtypingKleisli flatMap stange 类型参数子类型化
【发布时间】:2021-03-24 16:46:03
【问题描述】:

有人可以向我解释一下为什么猫中 Kelisli 的 flatMap 签名如下:

def flatMap[C, AA <: A](f: B => Kleisli[F, AA, C])(implicit F: FlatMap[F]): Kleisli[F, AA, C] =
    Kleisli.shift(a => F.flatMap[B, C](run(a))((b: B) => f(b).run(a)))

我其实不太明白的是AA &lt;: A为什么AA必须是A的子类型?

我得到了 Kleisli flatmap 操作,是我没有得到的 subTyping?

【问题讨论】:

标签: scala scala-cats


【解决方案1】:

因为你可以,而且有时它会让生活更轻松。

假设我们有一些子类型

trait Animal {
  def makeNoise: IO[Unit]
}

case class DogFood(label: String)

case class Dog(name: String) extends Animal {
  def makeNoise = IO.println(s"$name says Woof!")
  def consumeEdibles(df: DogFood) = IO.println(s"$name ate '${df.label}'. Yum!")
}

我们可以制作一些 Kleislis:

val doNoise = Kleisli((_: Animal).makeNoise)
val eatNewFood = Kleisli((_: Dog).consumeEdibles(new DogFood("Fancy Dog Food")))

请注意,它们中的第一个只需要Animal,但它们都可以使用Dog 调用。我们能够以某种方式将两者组合成一个可以用狗叫的 Kleisli,这听起来很合理。正确的?让我们试试吧。


如果你从 Dog Kleisli 开始,它就可以工作:

// Both valid - contravariance makes it so that doNoise : Kleisli[IO, Animal, Unit]
// extends Kleisli[IO, Dog, Unit] and compiler figures it out. Result is Kleisli[IO, Dog, Unit]
eatNewFood.flatMap(_ => doNoise)
(eatNewFood >> doNoise)

但请注意,您不能这样做:

(doNoise >> eatNewFood)

那是因为&gt;&gt; 是“愚蠢的”。由于您以Kleisli[IO, Animal, Unit] 开头,因此它要求下一个也是Kleisli[IO, Animal, something]

不过,我们可以通过告诉编译器在推断 &gt;&gt; 的类型之前扩大 Kleisli 来纠正它:

((doNoise: Kleisli[IO, Dog, Unit]) &gt;&gt; eatNewFood)

这是冗长而丑陋的。如果我们能告诉“嘿,而不是要求右手边是更宽的类型,而是允许结果是对两者都有效的更窄的类型”,那就太好了。


这正是flatMap 签名所说的。子类型意味着更窄的 AA 类型可以代替更宽的类型 A 用于左侧和右侧。

// Valid because of this trick you're asking about
// Here AA = Dog <: Animal = A
// Result value is Kleisli[F, AA, C] which resolves to Kleisli[IO, Dog, Unit]
doNoise.flatMap(_ => eatNewFood)

我们失去的只是一些用于缩小输入范围的类型归属,没有人喜欢这些。

注意 AA 和 A 相同满足 AA <: a>必须是不同的子类型,但它可以而且它既合法又有意义(可以用 Dog 调用两者 => 可以将它们组合成可以用 Dog 调用的东西)。

【讨论】:

  • 谢谢你。将对其进行测试并返回
猜你喜欢
  • 2016-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 1970-01-01
  • 2021-02-13
相关资源
最近更新 更多