I translate my problem in this little "oversimplified" example. Objective is to return only the latest computation based on a simple function execution on each element of an iterator object.
val l = List(1,2,3,4).toIterator
def myPersonnalMultiply(number:Int) = number * 2
For this list, i want my iterator evaluation return '8'
I started to try with a yield
, but it seems i cannot compute two things like that :
val result = for (
e <- l
computation = myPersonnalMultiply(e)
if ((l.hasNext) == false) yield computation
So, there is the solution to map
then slice
to conserve only the latest element evaluated, but after discussion with a collegue, it seems this is not really beautiful functionnal code compliant, and there is a better approach to do that (really ? ).
Based on this, i want to iterate and compute my function on all element of the list, but only the latest computation is returned.
Edit : my exemple is "too oversimplified", sorry for this mistake.
In reality, equivalent to myPersonallMultiply function equal an execution of a simulation which can need current state, or the previous state to be computed.
The states function of my simulator return an iterator of 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))
}
When you compute each of this state (step of my simulation = 1 state) you need to store/write result anywhere, so i encapsulate run of simulation into a Writer class, here a '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 - As you can see, here, each step don't need the previous state, but in a really near future, this is the case : for example, to compute new exchange between our cities in our simulation a state T, we need to access to the exchanger created at the previous state T-1
2 - I need to return the last state to compute some score for my simulation, so i need the CSVWriter class write each state returned by s.states, and return also the last state computed.
3 I think it's possible to create a better and more generic solution for this problem : perhaps the reader monad
can help me to create a better interface for this complex writer behaviour for state iterator but perhaps i mistake ?
I hope my question is more clear.
After some research i found the monad reader
functionnal pattern, but if i understand globally the interest of this approach, i don't understand how i can translate the different example i read on the web ( like the first example here http://mergeconflict.com/reading-your-future/ ) to this simple problem. I try different code without success at this time :/
Do you have some simple explanation or pointers to help me understand the 'monad reader' ?
Or perhaps i totally mistake, and i can't resolve my problem with this approach ?
Maybe you oversimplified your case, but if you need to process all the elements indipendently (meaning that the result of your operation on the ith-element is not needed for operation on the ith+1-element) you don't need a monad.
You can simply operate on all elements (even in parallel!), put the results back and get the last one