如何为函数类型定义单子?

发布于 2025-01-25 20:48:06 字数 1147 浏览 4 评论 0原文

我正在第一次尝试猫,并且正在使用Scala 3,但是我正在尝试实施一组解析器组合者以自行自同学。我被关注tailRecm单元的函数的定义。我已经管理函数和应用程序。

我将所讨论的类型定义为一个函数:

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 
      }
  }

如果我尝试构建,我会得到“找到:解析。需要:parsing.parseresult [b]“ for tailRecm(a)(fn)

我可以说的是,我的类型<我的类型<, 代码>解析器[A] 是函数类型,而不仅仅是值类型?我试图通过修改tailRecm递归调用tailRecm(a)(fn)(input)(输入)来改善问题,但显然这也不是安全的,并且也不会安全,并且也不会安全。编译。

我该如何解决这个问题,更广泛地解决一般的功能类型的单调类型?

I am trying Cats for the first time and am using Scala 3, and I am trying to implement a set of parser combinators for self-pedagogy, however; I am stuck on the definition of the tailRecM function for Monad. I have managed Functor and Applicative just fine.

I have defined my type in question as a function such that:

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

with corresponding return types as:

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

My current definition of tailRecM is as follows:

@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 
      }
  }

If I attempt to build I get "Found: Parsing.Parser[B] Required: Parsing.ParseResult[B]" for tailRecM(a)(fn)

The issue as far as I can tell stems from the fact that my type in question Parser[A] is a function type and not simply a value type? I attempted to ameliorate the issue by modifying the tailRecM recursive call to tailRecM(a)(fn)(input) but then this is obviously not stack safe, and also will not compile.

How can I resolve this issue, and more broadly, how can I implement the Monad typeclass for function types in general?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

耳钉梦 2025-02-01 20:48:06

不可能使tailRecm本身本身进行尾声;您需要定义一个尾部回复辅助方法

,这是cats library实现tailRecmfunction> function1

  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)
    }

这是因为monadic递归是< em>相互访问,其中两种方法互相呼唤。 Scala编译器无法优化。因此,我们将其嵌入式元素定义,而不是调用flatmap或其他方法

It's not possible to make tailRecM itself tail-recursive; you need to define a tail-recursive helper method

Here's how the cats library implements tailRecM for Function1

  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)
    }

This is because monadic recursion is a form of mutual tail-recursion, where two methods flip back and forth calling each other. The scala compiler can't optimize that. So instead we inline the definition of the monadic part rather than calling flatMap or another method

陪你到最终 2025-02-01 20:48:06

您需要再次将输入再次传递到tailRecm呼叫

tailRecM(a)(fn)(input)

,因为tailRecm(a)(fn)(fn)返回parser ,但是您需要从该返回的Parser中的parserresult,就像您在所有其他情况下一样。

You need to pass the input again to the tailRecM call

tailRecM(a)(fn)(input)

because tailRecM(a)(fn) returns a Parser, but you need the ParserResult from that returned Parser, as you already did in all other cases.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文