我想使用monad來實作一個表示while回圈的函式。
我是這樣做的:Statecats
def whileLoopState[S](cond: S => Boolean)(block: S => S): State[S, Unit] = State { state =>
if (cond(state)) {
val nextState = block(state)
whileLoopState(cond)(block).run(nextState).value
} else {
(state, ())
}
}
這個實作的問題是它不是堆疊安全的,因為遞回呼叫不在尾部位置,所以下面會導致堆疊溢位錯誤:
whileLoopState[Int](s => s > 0) { s =>
println(s)
s - 1
}.run(10000).value
CatstailRecM為每個Monadtrait 實體實作了方法,允許使單子遞回函式堆疊安全:
type WhileLoopState[A] = State[Unit, A]
def whileLoopStateTailRec[S](cond: S => Boolean)(block: S => S)(initialState: S): WhileLoopState[S] = Monad[WhileLoopState]
.tailRecM(initialState) { newState =>
State { _ =>
if (cond(newState)) {
val nextState = block(newState)
((), Left(nextState))
} else {
((), Right(newState))
}
}
}
現在這有效:
whileLoopStateTailRec[Int](s => s > 0) { s =>
println(s)
s - 1
} (10000).run().value
但是對于像這樣的簡單案例,實施whileLoopStateTailRec似乎太復雜了,因此引起了我的懷疑,即我沒有正確地做事。
有沒有辦法簡化它?
是否可以使用State[A, Unit]而不是State[Unit, A]使狀態保持在正確的插槽中?是否可以在不使用 monad 堆疊的情況下
使遞回函式安全?StatetailRecM
uj5u.com熱心網友回復:
您可以像這樣利用flatMaponState是堆疊安全的:
def whileLoopState[S](cond: S => Boolean)(block: S => S): State[S, Unit] =
State.get[S].flatMap { s =>
if (cond(s)) State.set(block(s)) >> whileLoopState(cond)(block)
else State.pure(())
}
或者,更好的是,重用現有語法:
def whileLoopState[S](cond: S => Boolean)(block: S => S): State[S, Unit] =
State.modify(block).whileM_(State.inspect(cond))
您可以看到這里運行的代碼。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/528334.html
標籤:斯卡拉递归单子斯卡拉猫
上一篇:Python:使用遞回列印串列
下一篇:遞回輸出不列印
