如何约束F[_]成为Monad实例以使用flatMap?
给
Creator类的F[_]加上Monad约束,顺利使用flatMap 嘿,我来帮你搞定这个问题!首先得明确一点:在Cats生态里,Sync[F]其实已经自带了Monad的能力——因为Sync继承自MonadError[F, Throwable],而MonadError又继承了Monad[F]。不过如果你需要显式约束,或者之前因为语法导入问题没法用flatMap,可以试试下面两种方案:
方案1:显式添加Monad隐式参数
直接在类的隐式参数列表里加上Monad[F],这样就能明明白白确保F是Monad实例,后续用flatMap完全没问题:
import cats.Monad import cats.effect.Sync final case class Creator[F[_]](topic: String, discovery: ServiceDiscovery[F])( implicit sync: Sync[F], monad: Monad[F] // 显式声明Monad约束 ) { import JsonDeserializer._ // 注意:这里返回类型要改成F[ConsumerSettings[...]],因为flatMap会保留F上下文 private def setting: F[ConsumerSettings[F, String, JsonDecoder]] = discovery.kafkaAddr .flatMap { addr => // 这里写你需要的逻辑,比如用地址构建ConsumerSettings Sync[F].pure(ConsumerSettings[F, String, JsonDecoder].withBootstrapServers(addr)) } .flatMap { baseSettings => // 继续链式调用flatMap,比如添加groupId之类的配置 Sync[F].pure(baseSettings.withGroupId(s"${topic}-group")) } }
方案2:利用Sync自带的Monad能力(更简洁)
既然Sync[F]已经隐含了Monad实例,那我们不需要额外加参数,只需要导入Cats的语法扩展,就能直接用flatMap:
import cats.effect.Sync import cats.syntax.flatMap._ // 关键:导入flatMap的语法扩展 final case class Creator[F[_]](topic: String, discovery: ServiceDiscovery[F])( implicit sync: Sync[F] ) { import JsonDeserializer._ private def setting: F[ConsumerSettings[F, String, JsonDecoder]] = discovery.kafkaAddr .flatMap { addr => Sync[F].pure(ConsumerSettings[F, String, JsonDecoder].withBootstrapServers(addr)) } }
小提醒:
你原来的代码里setting的返回类型是ConsumerSettings[F, String, JsonDecoder],但discovery.kafkaAddr应该是F[String](或者其他被F包裹的类型),flatMap之后返回的还是F[ConsumerSettings[...]],所以一定要调整返回类型哦!如果直接想拿到纯值,虽然可以用unsafeRunSync(),但不建议在类内部这么做——最好保留F的上下文,让调用方决定何时执行。
另外,如果之前没法用flatMap,大概率是忘了导入cats.syntax.flatMap._这个语法扩展包,加上就好了~
内容的提问来源于stack exchange,提问作者softshipper
相关产品推荐
相关产品推荐

