Несколько недель назад Dragisa Krsmanovic задал вопрос здесь о том, как использовать свободную монаду в Scalaz 7, чтобы избежать в этой ситуации (я немного адаптировал его код):
import scalaz._, Scalaz._
def setS(i: Int): State[List[Int], Unit] = modify(i :: _)
val s = (1 to 100000).foldLeft(state[List[Int], Unit](())) {
case (st, i) => st.flatMap(_ => setS(i))
}
s(Nil)
Я думал, что что нужно просто поднимать батут в StateT
:
import Free.Trampoline
val s = (1 to 100000).foldLeft(state[List[Int], Unit](()).lift[Trampoline]) {
case (st, i) => st.flatMap(_ => setS(i).lift[Trampoline])
}
s(Nil).run
Но он все еще ударяет стек, поэтому я просто разместил его как комментарий.
Дэйв Стивенс просто указал, что последовательность с аппликативным *>
вместо монадического flatMap
на самом деле работает просто отлично:
val s = (1 to 100000).foldLeft(state[List[Int], Unit](()).lift[Trampoline]) {
case (st, i) => st *> setS(i).lift[Trampoline]
}
s(Nil).run
(Ну, это очень медленно, конечно, потому что цена, которую вы платите за то, что делает что-нибудь интересное, как это в Scala, но по крайней мере там нет.)
Что здесь происходит? Я не думаю, что для этой разницы может быть принципиальная причина, но на самом деле я понятия не имею, что может произойти в реализации, и у меня нет времени копаться в данный момент. Но мне любопытно, и было бы здорово, если бы кто-то еще знал.