繁体   English   中英

如何为 function 类型定义 Monad?

[英]How to define a Monad for a function type?

我是第一次尝试 Cats,我正在使用 Scala 3,但是我正在尝试实现一组用于自我教学的解析器组合器; 我停留在 Monad 的tailRecM function 的定义上。 我已经很好地管理了 Functor 和 Applicative。

我已将我的相关类型定义为 function,这样:

type Parser[A] = (input: List[Token]) => ParseResult[A]

相应的返回类型为:

type ParseResult[A] = Success[A] | Failure 
case class Success[A](value: A, tokens: List[Token])
case class Failure(msg: String, tokens: List[Token])

我目前对tailRecM的定义如下:

@annotation.tailrec
def tailRecM[A, B](init: A)(fn: A => Parser[Either[A, B]]): Parser[B] =
  (input: List[Token]) => 
    fn(init)(input) match {
      case f: Failure => f
      case s: Success[Either[A, B]] => s.value match {
        case Right(b) => Success(b, s.tokens)
        case Left(a) => tailRecM(a)(fn) // won't compile 
      }
  }

如果我尝试构建,我会得到"Found: Parsing.Parser[B] Required: Parsing.ParseResult[B]" for tailRecM(a)(fn)

据我所知,这个问题源于我的问题Parser[A]类型是 function 类型而不仅仅是值类型这一事实? 我试图通过修改对tailRecM(a)(fn)(input)tailRecM递归调用来改善这个问题,但这显然不是堆栈安全的,也不会编译。

我如何解决这个问题,更广泛地说,我如何为 function 类型实现 Monad 类型类?

使tailRecM本身成为尾递归是不可能的; 您需要定义一个尾递归辅助方法

以下是cats库如何为Function1实现tailRecM

  def tailRecM[A, B](a: A)(fn: A => T1 => Either[A, B]): T1 => B =
    (t: T1) => {
      @tailrec
      def step(thisA: A): B =
        fn(thisA)(t) match {
          case Right(b)    => b
          case Left(nextA) => step(nextA)
        }
      step(a)
    }

这是因为单子递归是相互尾递归的一种形式,其中两个方法来回调用彼此。 scala 编译器无法对其进行优化。 因此,我们内联 monadic 部分的定义,而不是调用flatMap或其他方法

您需要再次将input传递给tailRecM调用

tailRecM(a)(fn)(input)

因为tailRecM(a)(fn)返回一个Parser ,但是您需要从返回的ParserParserResult ,就像您在所有其他情况下所做的那样。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM