我们正在创建我们自己的OptionT
猫来理解,monad是如何工作的和monads转换流程。在创建我们自己的自定义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
以下是我们陷入困境的要点:
WhateverOpt
flatMap
方法中的无案例?Error:(26, 12) could not find implicit value for parameter M: usercases.mtransfomer.Monad[scala.concurrent.Future]
addres <- WhateverOpt(repository.getAddressOption(user))
我们不确定错误,因为我们正在隐式创建optionTMonad
,默认情况下,所有错误都在同一范围内。我们如何解决这两个问题?
更新
完整代码可在Github分支https://github.com/harmeetsingh0013/fp_scala/blob/master/src/main/scala/usercases/mtransfomer/Example5.scala
上找到答案 0 :(得分:1)
如何处理WhateverOpt flatMap方法中的无案例?
当你flatMap
超过None
时,你会返回None
。当您flatMap
超过WhateverOpt[W[_], B]
时,您想要返回pure
的{{1}},代码中的M.pure(None)
将为Error:(26, 12) could not find implicit value for parameter M: usercases.mtransfomer.Monad[scala.concurrent.Future]
addres <- WhateverOpt(repository.getAddressOption(user))
。
执行代码时,出现运行时错误:
Monad[Future]
这是一个编译时错误(不是运行时错误),而是由于缺少Monad[Future]
的实例。为了在猫的范围内获得import cats.instances.future._
import scala.concurrent.ExecutionContext.Implicits.global
的实例,你可以这样做:
Monad[Option]
此外,您可以避免通过使用
从猫中导入来声明自己的import cats.instances.option._
bool fileExists(const char* filename)
{
FILE* fp = fopen(filename, "r");
bool result = (fp != NULL);
if (result) fclose(fp);
return result; // <-- (cppcheck error) Resource leak: fp
}
答案 1 :(得分:1)
关于如何处理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
。然后上面的代码说:
value
产生oa
类型的结果Option[A]
oa
原来是None
,那么我们无能为力,因为我们无法获取A
类型的任何实例来调用f
。因此,请立即返回None
。 immediately return
是pure
- monad的Future
- 方法,因此对于一般情况,我们必须调用wMonad.pure(None)
。oa
产生Some(a)
,我们可以将此a
提供给f
,然后立即解压缩以获得value
类型W[Option[B]]
1}}。 W[Option[B]]
(无论是empty
还是WhateverOpt
),我们可以将其打包到flatMap
并从Monad[Option]
方法返回。我认为你想重新实现catsStdInstancesForOption
只是为了好玩(它已经是in the library(CommutativeMonad
的东西是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
}
}
}
),但这是你怎么回事 - 建造它:
pure
请注意,1.0.1需要实现tailRecM
和future
,并且不提供默认实现。
我不想对Monad
的必要导入说多少,但最新版本有cats.instances.future,它提供tailRecM
个实例。请再次检查,因为您似乎使用的是不同版本的猫(由于Option
- monad中缺少//
,您的版本没有投诉。
答案 2 :(得分:1)
如何处理WhateverOpt flatMap方法中的无案例?
@Gabriele Petronella 和 @Andrey Tyukin 详细解释了这个答案。
执行代码时,获取运行时错误:错误:(26,12)可以 找不到参数M的隐含值: usercases.mtransfomer.Monad [scala.concurrent.Future] addres&lt; - WhateverOpt(repository.getAddressOption(用户))
发生此错误,因为在WhateverOpt
构造函数中,我们知道我们的值为W[Option[A]]
,其中Option
已经定义并由代码处理,但repository.getUserOption(1)
返回{ {1}} Future[Option[User]]
由通用参数Future
处理,在这种情况下,我们需要定义如何处理W
的monad。要解决该问题,我们需要实施Future
而不是new Monad[Future]
,如下所示:
new Monad[Option]
我不确定我的回答,我在回答中提到过,但目前我的假设是这样的,对我而言,上面的代码工作正常。有关完整示例,请单击问题中提及的GitHub仓库。