0

私の問題をこの少し「単純化しすぎた」例に置き換えます。目的は、反復子オブジェクトの各要素に対する単純な関数の実行に基づいて、最新の計算のみを返すことです。

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

このリストでは、反復子の評価が '8' を返すようにします

を試してみましたyieldが、そのような2つのことを計算できないようです:

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が、このアプローチの関心をグローバルに理解している場合、Webで読んだ別の例をどのように翻訳できるかわかりません(ここの最初の例のようにhttp://mergeconflict.com /reading-your-future/ ) をこの単純な問題に当てはめます。現時点では成功せずに別のコードを試しています:/

「モナドリーダー」を理解するのに役立つ簡単な説明や指針はありますか?

または、おそらく私は完全に間違っており、このアプローチで問題を解決できませんか?

4

2 に答える 2

1

foldLeft を単純に (ab) 使用できます。

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

wheremyDefaultValueは、リストが空の場合に返される値です。

于 2012-10-23T16:10:43.250 に答える
1

ケースを単純化しすぎたかもしれませんが、すべての要素を個別に処理する必要がある場合(つまり、 i 番目の要素に対する操作の結果は、i 番目の要素に対する操作には必要ありません)、モナドは必要ありません。

すべての要素を操作するだけで (並列でも!)、結果を元に戻し、最後の要素を取得できます。

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 に答える