Я перевожу свою проблему в этот небольшой «упрощенный» пример. Цель состоит в том, чтобы вернуть только последние вычисления, основанные на выполнении простой функции для каждого элемента объекта итератора.
val l = List(1,2,3,4).toIterator
def myPersonnalMultiply(number:Int) = number * 2
Для этого списка я хочу, чтобы моя оценка итератора возвращала «8»
Я начал пытаться с yield
, но, похоже, я не могу вычислить две вещи:
val result = for (
e <- l
computation = myPersonnalMultiply(e)
if ((l.hasNext) == false) yield computation
Таким образом, есть решение map
, затем slice
, чтобы сохранить только последний оцененный элемент, но после обсуждения с коллегой кажется, что это на самом деле не соответствует красивому функциональному коду, и есть лучший подход к сделать это (правда?).
Исходя из этого, я хочу выполнить итерацию и вычислить свою функцию для всех элементов списка, но возвращается только последнее вычисление.
Редактировать: мой пример "слишком упрощен", извините за эту ошибку.
На самом деле эквивалент функции myPersonallMultiply эквивалентен выполнению симуляции, для которой может потребоваться вычисление текущего состояния или предыдущего состояния.
Функция состояний моего симулятора возвращает итератор состояния:
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/ ) к этой простой задаче. В настоящее время я безуспешно пробую другой код:/
Есть ли у вас какое-нибудь простое объяснение или указатели, которые помогут мне понять «читатель монад»?
Или, может быть, я полностью ошибаюсь и не могу решить свою проблему с помощью этого подхода?
list.view.map(...).last
? - person kiritsuku   schedule 23.10.2012last
нет ничего нефункционального. - person Travis Brown   schedule 23.10.2012s.states.last
после блокаtry/catch
. Для получения дополнительной информации о потоке состояния для шага симуляции, я предполагаю, что вы смотрите не на ту монаду: вам следует взглянуть на монадуState
. Некоторые примеры здесь. - person pagoda_5b   schedule 24.10.2012s.states
в последовательность, как вs.states.toSeq
, прежде чем вызыватьlast
. Вы можете создатьval steps = s.states.toSeq
перед вызовомforeach
, а затемlast
- person pagoda_5b   schedule 24.10.2012