что такое правильное понимание монады или последовательности как для карты, так и для переноса состояния?

Я пишу переводчик языка программирования.

Мне нужна правильная идиома кода, чтобы как оценить последовательность выражений, чтобы получить последовательность их значений, так и передать состояние от одного оценщика к следующему по мере выполнения вычислений. Я'Мне бы понравилась функциональная идиома программирования для этого.

Это'это не сгиб, потому что результаты получаются как карта. Это'не карта из-за государственной поддержки.

Что у меня есть этот код, который яЯ использую, чтобы попытаться понять это. Сначала перенесите несколько линий испытательного стенда:

// test rig
class MonadLearning extends JUnit3Suite {

  val d = List("1", "2", "3") // some expressions to evaluate. 

  type ResType = Int 
  case class State(i : ResType) // trivial state for experiment purposes
  val initialState = State(0)

// my stub/dummy "eval" function...obviously the real one will be...real.
  def computeResultAndNewState(s : String, st : State) : (ResType, State) = {
    val State(i) = st
    val res = s.toInt + i
    val newStateInt = i + 1
    (res, State(newStateInt))
  }

Мое текущее решение. Использует переменную, которая обновляется при оценке тела карты:

  def testTheVarWay() {
    var state = initialState
    val r = d.map {
      s =>
        {
          val (result, newState) = computeResultAndNewState(s, state)
          state = newState
          result
        }
    }
    println(r)
    println(state)
  }

У меня есть то, что я считаю неприемлемыми решениями, используя foldLeft, который делает то, что я называю "Сумка, как вы сложите " идиома:

def testTheFoldWay() {

// This startFold thing, requires explicit type. That alone makes it muddy.
val startFold : (List[ResType], State) = (Nil, initialState)
val (r, state) = d.foldLeft(startFold) {
  case ((tail, st), s) => {
    val (r, ns) = computeResultAndNewState(s, st)
    (tail :+ r, ns) // we want a constant-time append here, not O(N). Or could Cons on front and reverse later
  }
}

println(r)
println(state)

}

У меня также есть пара рекурсивных вариантов (которые очевидны, но также не ясны или хорошо мотивированы), один из которых использует потоки, которые почти терпимы:

def testTheStreamsWay() {
  lazy val states = initialState #:: resultStates // there are states
  lazy val args = d.toStream // there are arguments
  lazy val argPairs = args zip states // put them together
  lazy val resPairs : Stream[(ResType, State)] = argPairs.map{ case (d1, s1) => computeResultAndNewState(d1, s1) } // map across them
  lazy val (results , resultStates) = myUnzip(resPairs)// Note .unzip causes infinite loop. Had to write my own.

  lazy val r = results.toList
  lazy val finalState = resultStates.last

  println(r)
  println(finalState)
}

Но я могу'что-нибудь компактное или четкое, как оригиналвар» Решение выше, которое яЯ хочу жить с, но я думаю, что кто-то, кто ест / пьет / спит идиомы монады собирается просто сказать ... использовать это ... (Надеюсь!)

Ответы на вопрос(3)

Ваш ответ на вопрос