让 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 不是 MonadListEitherOption 或您可能认为的任何其他数据类型也不是。它们都形成Monad(另一种说法是它们有一个与之关联的Monad 实例)。这是 typeclass 和传统 subtyping 之间的主要区别之一,理解这一点很重要,因此您可以了解为什么 F[_] : Monad 有效而 F[_] &lt;: 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的主要内容,如果未能解决你的问题,请参考以下文章

Functor& Monad解读

函数式夜点心:IO Monad 与副作用处理

让Monad来得更猛烈些吧_Haskell笔记11

Scala中的Monad特征

如何为continuation monad实现stack-safe chainRec操作符?

在IO monad中进行递归