让 F[_] 在接受 IO 的同时实现 Monad trait
Posted
技术标签:
【中文标题】让 F[_] 在接受 IO 的同时实现 Monad trait【英文标题】:Make F[_] implementing Monad trait while accepting IO 【发布时间】:2021-12-10 04:15:34 【问题描述】:假设我们有代码(<: Monad[F]
无法按预期工作):
class External[F[_] <: Monad[F] : Concurrent](implicit proxy: Proxy[F]) ...
class Proxy[F[_] <: Monad[F]](implicit storage: Storage, async: Async[F])
def get(key: String): F[Option[Entry]] =
async.blocking(storage.get(key))
我希望F[_]
成为Monad
,以便proxy.get()
具有这些特征并启用例如(在External
类中):
proxy.get(key).flatMap(...)
到目前为止一切顺利,但是当尝试使用 cats.effect.IO
实例化时,它不适用于 External
:
implicit val proxy: Proxy[IO] = new Proxy()
implicit val external: External[IO] = new External()
有错误输出:
inferred type arguments [[+A]cats.effect.IO[A]] do not conform to value <local External>'s type parameter bounds [F[_] <: cats.Monad[F]]
如何解决或以不同的方式实现?
【问题讨论】:
IO
不是 Monad
,List
、Either
、Option
或您可能认为的任何其他数据类型也不是。它们都形成Monad
(另一种说法是它们有一个与之关联的Monad
实例)。这是 typeclass 和传统 subtyping 之间的主要区别之一,理解这一点很重要,因此您可以了解为什么 F[_] : Monad
有效而 F[_] <: Monad
无效. - 顺便说一句,如果您删除糖语法,这更容易看到:class External[_](implicit ev1: Monad[F], ev2: Concurrent[F])
; PS:Concurrent
IS A Monad
因此你只需要那个
另外,如果您对这一切还很陌生,我建议您先坚持使用具体的 IO
一段时间,然后再深入了解通常所说的 “无标签决赛”无论如何,请随意加入 typelevel discord 服务器,在那里您可能会寻求有关这种风格的更多指导。
@LuisMiguelMejíaSuárez 正确的介词在***.com/questions/68477132 中讨论过 :)
【参考方案1】:
替换
class External[F[_] <: Monad[F] : Concurrent]
与
class External[F[_]: Monad : Concurrent]
成为Monad
并不意味着成为Monad
的子类型。这意味着当前类型存在类型类Monad
的实例。
与 OOP 不同,在 FP 中实现一些抽象行为不是通过扩展/继承/子类型多态性而是通过隐式/定义类型类实例/ad hoc 多态性来实现的。
也许你需要导入必要的语法:
import cats.syntax.flatMap._
或
import cats.syntax.functor._
或同时使用所有的语法
import cats.syntax.all._
How to enforce F[_] to be an instance of Monad
https://eed3si9n.com/herding-cats/import-guide.html
【讨论】:
不够,从那时起proxy.get()
将没有Monad
特征。
@scala-n00b 也许你需要导入语法***.com/questions/58150448/…
@scala-n00b 不,这正是因为导入语法。 scastie.scala-lang.org/DmytroMitin/UjF8GBFRTlqF3ZHiO2eTOw/1 只是 Functor
语法,而不是 FlatMap
语法。
@scala-n00b 通常比 import cats.syntax.all._
更好,因为这样您将获得所有语法,并且您不需要关心层次结构的哪一部分提供了它。
@DmytroMitin 同意,我认为我之前的评论在某处缺少 "beginners" :)以上是关于让 F[_] 在接受 IO 的同时实现 Monad trait的主要内容,如果未能解决你的问题,请参考以下文章