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
overNone
时,返回None
。当您flatMap
overWhateverOpt[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,实际上不是:)@HarmeethightaraMonad[未来]
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