0

我在这个“过于简单”的小例子中翻译了我的问题。目标是仅返回基于对迭代器对象的每个元素的简单函数执行的最新计算。

val l = List(1,2,3,4).toIterator
def myPersonnalMultiply(number:Int) = number * 2

对于这个列表,我希望我的迭代器评估返回 '8'

我开始尝试使用 a yield,但似乎我无法计算这样的两件事:

val result = for (
  e <- l
  computation = myPersonnalMultiply(e)
if ((l.hasNext) == false) yield computation

因此,有一个解决方案是mapslice保留最新评估的元素,但在与同事讨论后,这似乎不是真正漂亮的功能代码兼容,并且有更好的方法来做到这一点(真的吗?)。

基于此,我想在列表的所有元素上迭代和计算我的函数,但只返回最新的计算。

编辑:我的例子是“过于简单化”,对不起这个错误。

实际上,等效于 myPersonallMultiply 函数等于执行可能需要当前状态或要计算的先前状态的模拟。

我的模拟器的 states 函数返回 state 的迭代器:

 def states(implicit aprng: Random = new Random): Iterator[State] = {

    // Initial State loaded from file
    val loadedState = initState(this.getClass.getClassLoader.getResourceAsStream("init-situation.txt"))
    val territory = computeTerritory(loadedState)

    def simulationStep(state: State): State = {
        // 3b - Apply on each city the function evolveCity() which contain the sequence of action for each city
        // and return a list of tuple (city, exchange) which represent a new state at time t+1 for these cities
        val evolved =
          state.cities.map {
            city => evolveCity(city.id, state.cities, territory(city.id), state.date)
          }

        // 4 - take only the first object (cities) in the list "evolved"
        new State {
          val cities = evolved.map { case(city, _) => city }
          val date = state.date + 1
        }        
    }

    def ended(state: State) = {
      val maxInnov = maxInnovation(state.cities)
      val maxCity = maxCities(state.cities)

      // 3a - Break the simulation loop if one of these conditions is true
      state.date >= 4000 || /*maxPop > 70.0 || */ maxInnov > maxInnovation
    }

    // 1 - Launch the recursive simulation loop with initial loaded step, a the date 1
    val initialState: State = new State {
      val cities = loadedState
      val date = 1
    }

    Iterator.iterate(initialState)(simulationStep).takeWhile(s => !ended(s))
  }

当您计算每个状态(我的模拟步骤 = 1 个状态)时,您需要在任何地方存储/写入结果,因此我将模拟运行封装到一个 Writer 类中,这里是一个“CSVwriter”。

class CSVWriter(path: String, idExp:Int, seed:Long) {

  def apply(s: Simulation)(implicit aprng: Random) = {
    val writer = new BufferedWriter(new FileWriter(new File(path)))

    // TODO: Reader Nomad ? http://mergeconflict.com/reading-your-future/
    // Run stepWriter on each state, and write the result
    // Actually this code run the writer but don't return the final state ...

    try {
      writer.append("v_idn, v_exp, v_ticks, v_seed, v_pop" + "\n")
      s.states.foreach(stepWriter(_, writer))
    } finally writer.close
   }

  def stepWriter(dataToWrite: State, writer: Writer) = {
    writer.synchronized {
      val cities = dataToWrite.cities
      val year = dataToWrite.date
      cities.map {
        c => writer.append(List[Any](c.id.toInt, idExp.toInt, year.toInt, seed, c.population).map{_.toString}.mkString(",") + "\n")
      }
    }
  }

}

1 - 正如你所看到的,在这里,每一步都不需要先前的状态,但在不久的将来,情况就是这样:例如,要在我们的模拟状态 T 中计算我们的城市之间的新交换,我们需要访问在先前状态 T-1 创建的交换器

2 - 我需要返回最后一个状态来为我的模拟计算一些分数,所以我需要 CSVWriter 类写入 s.states 返回的每个状态,并返回计算的最后一个状态。

3 我认为可以为这个问题创建一个更好、更通用的解决方案:也许reader monad可以帮助我为状态迭代器的这种复杂的写入器行为创建一个更好的接口,但也许我错了?

我希望我的问题更清楚。

经过一些研究,我发现了monad reader功能模式,但是如果我在全球范围内了解这种方法的兴趣,我不明白如何翻译我在网上阅读的不同示例(就像这里的第一个示例http://mergeconflict.com /reading-your-future/)解决这个简单的问题。我此时尝试不同的代码但没有成功:/

你有一些简单的解释或指示来帮助我理解“单子阅读器”吗?

或者也许我完全错了,我无法用这种方法解决我的问题?

4

2 回答 2

1

您可以简单地(ab)使用 foldLeft:

val myDefaultValue = 0
l.foldLeft(myDefaultValue){ (_,x) => myPersonnalMultiply(x) }

wheremyDefaultValue是在列表为空的情况下返回的值。

于 2012-10-23T16:10:43.250 回答
1

也许您过于简化了您的情况,但是如果您需要单独处理所有元素(这意味着对 ith -element 的操作不需要ith +1 -element 进行操作),则不需要 monad。

您可以简单地对所有元素进行操作(甚至是并行操作!),将结果放回去并获得最后一个

def doAndGetLast[A, B](input: List[A])(computation: A => B): B = 
    (input.par map computation).seq.last

val inputs = List(1,2,3,4)

def myMul(n: Int) = n * 2

val withInputs: (Int => Int) => Int = doAndGetLast(inputs) _

val result = withInputs(myMul) // or directly doAndGetLast(inputs)(myMul)
于 2012-10-23T18:39:17.137 回答