[英]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.