【问题标题】:Scala Cats: tail recursive tailRecM method for Monad Instance of Task[Validated[String,?]Scala Cats:用于任务 [Validated[String,?] 的 Monad 实例的尾递归 tailRecM 方法
【发布时间】:2019-03-09 06:45:24
【问题描述】:

cats 中,当使用Monad 特征创建Monad 时,理想情况下,应提供方法tailRecM 的尾递归实现以确保堆栈安全。

我正在使用无标记的最终方法,并希望对我的程序产生Task[Validated[String, ?]] (Monix Task) 的效果。

我不知道如何编写尾递归实现。我的非尾递归解决方案是:

import cats.Monad
import cats.data.Validated
import cats.data.Validated.{Invalid, Valid}
import monix.eval.Task

final case class TaskValidated[A](value: Task[Validated[String, A]])

implicit val taskValidatedMonad: Monad[TaskValidated] = 
    new Monad[TaskValidated] {

        override def flatMap[A, B](fa: TaskValidated[A])(f: A => TaskValidated[B]): TaskValidated[B] =  
            new TaskValidated[B](   
                fa.value.flatMap {  
                    case Valid(a)   => f(a).value   
                    case Invalid(s) => Task(Invalid(s)) 
                }   
            )

        override def pure[A](a: A): TaskValidated[A] = TaskValidated(Task(Valid(a)))

        // @annotation.tailrec  
        def tailRecM[A, B](init: A)(fn: A => TaskValidated[Either[A, B]]): TaskValidated[B] = { 
            TaskValidated(fn(init).value.flatMap {  
                case Invalid(s)      => Task.now(Invalid(s))    
                case Valid(Right(b)) => Task.now(Valid(b))  
                case Valid(Left(a))  => tailRecM(a)(fn).value   
            })  
        }   
    }

【问题讨论】:

    标签: monads tail-recursion scala-cats monix tagless-final


    【解决方案1】:

    Task 有自己的tailRecM,所以使用它是有意义的。试试

    def tailRecM[A, B](init: A)(fn: A => TaskValidated[Either[A, B]]): TaskValidated[B] = {
      def aux(fn: A => Task[Validated[String, Either[A, B]]]): Task[Validated[String, B]] = {
        def fn1(a: A): Task[Either[A, B]] = fn(a).flatMap {
          case Valid(either) => Task.now(either)
          case Invalid(s)    => Task.raiseError(new RuntimeException(s))
        }
    
        Task.tailRecM(init)(fn1).map(Valid(_))
      }
    
      TaskValidated(aux(fn(_).value))
    }
    

    【讨论】:

      猜你喜欢
      • 2017-11-14
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      • 2019-06-04
      • 2020-07-13
      • 1970-01-01
      • 2015-06-25
      • 2018-03-17
      相关资源
      最近更新 更多