[英]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
,但是您需要从返回的Parser
中ParserResult
,就像您在所有其他情况下所做的那样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.