私の問題をこの少し「単純化しすぎた」例に置き換えます。目的は、反復子オブジェクトの各要素に対する単純な関数の実行に基づいて、最新の計算のみを返すことです。
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
したがって、評価された最新の要素のみを保存するための解決策がありますがmap
、slice
同僚との議論の後、これは実際には美しい関数コードに準拠していないようであり、それを行うためのより良いアプローチがあります (本当に?)。
これに基づいて、リストのすべての要素に対して関数を反復して計算したいのですが、最新の計算のみが返されます。
編集:私の例は「単純化しすぎ」です。この間違いをお詫びします。
実際には、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/ ) をこの単純な問題に当てはめます。現時点では成功せずに別のコードを試しています:/
「モナドリーダー」を理解するのに役立つ簡単な説明や指針はありますか?
または、おそらく私は完全に間違っており、このアプローチで問題を解決できませんか?