Scala:从CAT创建自定义OptionT monad以供学习

Scala:从CAT创建自定义OptionT monad以供学习,scala,monads,monad-transformers,scala-cats,Scala,Monads,Monad Transformers,Scala Cats,我们正在创建我们自己的猫的option,以了解单子是如何工作的以及单子的转换流程。在创建我们自己的自定义monad时,会出现一些错误。下面的第一件事是我们的代码: case class WhateverOpt[W[_], A] (value: W[Option[A]]) { def map[B] (f: A => B) (implicit M: Monad[W]): WhateverOpt[W, B] = WhateverOpt(M.map(value)(_.map(

我们正在创建我们自己的猫的
option
,以了解单子是如何工作的以及单子的转换流程。在创建我们自己的自定义monad时,会出现一些错误。下面的第一件事是我们的代码:

case class WhateverOpt[W[_], A] (value: W[Option[A]]) {

    def map[B] (f: A => B) (implicit M: Monad[W]): WhateverOpt[W, B] =
      WhateverOpt(M.map(value)(_.map(f)))

    def flatMap[B] (f: A => WhateverOpt[W, B]) (implicit M: Monad[W]): WhateverOpt[W, B] =
      WhateverOpt(M.flatMap(value)(optA => optA match {
        case Some(v) => f(v).value
      }))
  }

  implicit val optionTMonad = new Monad[Option] {

    override def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
    override def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)
  }

  val optionResult = for {
    user <- WhateverOpt(repository.getUserOption(1))
    addres <- WhateverOpt(repository.getAddressOption(user))
  } yield addres.city
case class WhateverOpt[W[]A](值:W[Option[A]]{
defmap[B](f:A=>B)(隐式M:Monad[W]):WhateverOpt[W,B]=
什么是绝对值(M.map(value)(u.map(f)))
def flatMap[B](f:A=>WhateverOpt[W,B])(隐式M:Monad[W]):WhateverOpt[W,B]=
WhateOveropt(M.flatMap(值)(optA=>optA匹配{
案例部分(v)=>f(v).值
}))
}
隐式val optionMonad=新单子[Option]{
覆盖def映射[A,B](fa:Option[A])(f:A=>B):Option[B]=fa.map(f)
覆盖def flatMap[A,B](fa:Option[A])(f:A=>Option[B]):Option[B]=fa.flatMap(f)
}
val optionResult=用于{
使用者
如何在WhateOveropt flatMap方法中处理无案例

当您
flatMap
over
None
时,返回
None
。当您
flatMap
over
WhateverOpt[W[\u],B]
时,您希望返回它的
pure
,它在您的代码中是
M.pure(None)

执行代码时,获取运行时错误:
error:(26,12)找不到参数M:usercases.mttransferomer.Monad[scala.concurrent.Future]的隐式值

addres关于如何处理
None

case class WhateverOpt[W[_], A] (value: W[Option[A]]) {

  def map[B] (f: A => B) (implicit M: Monad[W]): WhateverOpt[W, B] =
    WhateverOpt(M.map(value)(_.map(f)))

  def flatMap[B] 
    (f: A => WhateverOpt[W, B])
    (implicit wMonad: Monad[W])
  : WhateverOpt[W, B] = {
    WhateverOpt(wMonad.flatMap(value) { (oa: Option[A]) => 
      oa match {
        case None => wMonad.pure(None)
        case Some(a) => f(a).value
      }
    })
  }
}
想象一下,
W
Future
。然后上面的代码说:

  • 等待包装的
    产生类型为
    选项[a]
  • 如果
    oa
    结果是
    None
    ,那么我们无能为力,因为我们无法获得
    A
    类型的任何实例来调用
    f
    。因此,立即返回
    None
    立即返回
    未来的
    单子的
    方法,对于g一般情况下,我们必须调用
    wMonad.pure(None)
  • 如果
    oa
    产生
    一些(a)
    ,我们可以将该
    a
    交给
    f
    ,然后立即将其解压缩,得到
    W[选项[B]]
    类型的
  • 一旦我们有了
    W[Option[B]]
    (无论
    是否为空),我们就可以将它包装到
    WhateverOpt
    中,并从
    flatMap
    方法返回

我假设您想重新实现
Monad[Option]
只是为了好玩(它已经是了(
catsStdInstancesForOption
东西是一个
commercivemonad
),但下面是如何重新构建它:

implicit val optionTMonad = new Monad[Option] {
  override def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
  def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)
  def pure[A](a: A): Option[A] = Some(a)
  def tailRecM[A, B](a: A)(f: (A) => Option[Either[A, B]]): Option[B] = {
    f(a) match {
      case Some(Left(nextA)) => tailRecM(nextA)(f)
      case Some(Right(res)) => Some(res)
      case None => None
    }
  }
}
请注意,1.0.1要求实现
pure
tailRecM
,并且没有为此提供默认实现


我不想说太多关于
未来的必要导入
,但最新版本提供了一个
Monad
实例。请再次检查,因为您似乎正在使用不同版本的CAT(您的版本没有抱怨,因为
选项
-Monad中缺少
tailRecM

如何在WhateOveropt flatMap方法中处理无案例

加布里埃尔·佩特罗内拉和安德烈·图金已经详细解释了这个答案

执行代码时,获取运行时错误:error:(26,12)可能 找不到参数M的隐式值: usercases.mttransferomer.Monad[scala.concurrent.Future]addres B)(隐式M:Monad[W]):WhateverOpt[W,B]= 什么是绝对值(M.map(value)(u.map(f))) def flatMap[B](f:A=>WhateverOpt[W,B])(隐式M:Monad[W]):WhateverOpt[W,B]= WhateOveropt(M.flatMap(值)(optA=>optA匹配{ 案例部分(v)=>f(v).值 案例无=>M.pure(无) })) } 隐式val futureMonad=新单子[Future]{ 覆盖定义纯[A](A:A):未来[A]=未来。成功(A) 覆盖def映射[A,B](fa:Future[A])(f:A=>B):Future[B]=fa.map(f) 覆盖def flatMap[A,B](fa:Future[A])(f:A=>Future[B]):Future[B]=fa.flatMap(f) } val optionResult:WhateverOpt[Future,String]=for{
用户链接似乎不起作用,github提供404和一个jedi-octocat。谢谢,@Andreytukin您现在可以检查。你好@Gabriele,导入
导入cats.instances.future.\uImport scala.concurrent.ExecutionContext.Implicits.global
后,同样的错误正在发生。实际上,IntelliJ在编写code,这就是为什么我认为,这是运行时错误。Hello@Gabriele我找到了答案,我们需要声明
Monad[Future]
而不是,
Monad[Option]
因为我们知道
选项
是我们定制的
WhateverOpt
的一部分,但是未来是由泛型决定的,这就是为什么在这种情况下,我们需要定义
单子[Future]
用于隐式解析。@GabrielePetronella
选项的纯
?@Andreytukin woops,实际上不是:)@Harmeethightara
Monad[未来]
where?谢谢@Andrey的回答和解释。这对了解更多信息非常有帮助。但是根据我的代码和要求,而不是
new Monad[选项]
我们需要实现
new Monad[未来]
因为,我们知道
WhateverOpt
包含
选项
值,但是
Future
由泛型参数
W
处理,这就是为什么我们需要创建
新的Monad[Future]
。有关更多详细信息,请查看GitHub代码。@harmeetsinghtara实现
Monad[Future]
不会太难,因为
Future
已经实现了
flatMap
(这是最难的部分)。但正如我在回答中所说的:导入cats.instances.Future.\u
就足够了
case class WhateverOpt[W[_], A] (value: W[Option[A]]) {

  def map[B] (f: A => B) (implicit M: Monad[W]): WhateverOpt[W, B] =
    WhateverOpt(M.map(value)(_.map(f)))

  def flatMap[B] 
    (f: A => WhateverOpt[W, B])
    (implicit wMonad: Monad[W])
  : WhateverOpt[W, B] = {
    WhateverOpt(wMonad.flatMap(value) { (oa: Option[A]) => 
      oa match {
        case None => wMonad.pure(None)
        case Some(a) => f(a).value
      }
    })
  }
}
implicit val optionTMonad = new Monad[Option] {
  override def map[A, B](fa: Option[A])(f: A => B): Option[B] = fa.map(f)
  def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)
  def pure[A](a: A): Option[A] = Some(a)
  def tailRecM[A, B](a: A)(f: (A) => Option[Either[A, B]]): Option[B] = {
    f(a) match {
      case Some(Left(nextA)) => tailRecM(nextA)(f)
      case Some(Right(res)) => Some(res)
      case None => None
    }
  }
}
case class WhateverOpt[W[_], A] (value: W[Option[A]]) {

    def map[B] (f: A => B) (implicit M: Monad[W]): WhateverOpt[W, B] =
      WhateverOpt(M.map(value)(_.map(f)))

    def flatMap[B] (f: A => WhateverOpt[W, B]) (implicit M: Monad[W]): WhateverOpt[W, B] =
      WhateverOpt(M.flatMap(value)(optA => optA match {
        case Some(v) => f(v).value
        case None => M.pure(None)
      }))
  }

  implicit val futureMonad = new Monad[Future] {
    override def pure[A](a: A): Future[A] = Future.successful(a)

    override def map[A, B](fa: Future[A])(f: A => B): Future[B] = fa.map(f)

    override def flatMap[A, B](fa: Future[A])(f: A => Future[B]): Future[B] = fa.flatMap(f)
  }

  val optionResult: WhateverOpt[Future, String] = for {
    user <- WhateverOpt(repository.getUserOption(1))
    addres <- WhateverOpt(repository.getAddressOption(user))
  } yield addres.city