Подтвердить что ты не робот

Правильное использование изменяемых/неизменяемых списков

В настоящий момент Im пытается понять функциональное программирование в Scala, и я столкнулся с проблемой, которую я не могу понять сам.

Представьте себе следующую ситуацию:

У вас есть два класса: Controller и Bot. Бот - независимый Актер, который инициируется Контроллером, выполняет некоторую дорогостоящую операцию и возвращает результат Контроллеру. Таким образом, назначение контроллера легко описать: создать несколько объектов Bot, запустить их и получить результат.

До сих пор так хорошо; Я могу реализовать все это без использования каких-либо изменяемых объектов.

Но что мне делать, если мне нужно сохранить результат, который возвращает Bot, использовать его позже в качестве входа для другого Бот (а позже означает, что я не знаю, когда на время компиляции!)?

Выполнение этого с измененным списком или коллекцией довольно просто, но я добавляю много проблем в свой код (поскольку мы имеем дело с concurrency здесь).

Возможно ли, следуя парадигме FP, решить эту проблему, используя безопасные объекты (списки...)?

Кстати, я новичок в FP, поэтому этот вопрос может показаться глупым, но я не могу понять, как это решить:)

4b9b3361

Ответ 1

Вот как выглядит эрлангоподобный актер в Scala:

case class Actor[State](val s: State)(body: State => Option[State]) { // immutable
  @tailrec
  def loop(s1: State) {
    body(s1) match {
      case Some(s2) => loop(s2)
      case None => ()
    }
  }

  def act = loop(s)
}

def Bot(controller: Actor) = Actor(controller) { 
  s => 
    val res = // do the calculations
    controller ! (this, res)
    None // finish work
} 

val Controller = Actor(Map[Bot, ResultType]()) {s =>
  // start bots, perhaps using results already stored in s
  if ( 
    // time to stop, e.g. all bots already finished 
  )
    None
  else
    receive {
      case (bot, res) => Some(s + (bot -> res)) // a bot has reported result
    }
}

Controller.act

Ответ 2

Актеры обычно имеют внутреннее состояние, будучи самим собой, изменчивыми животными. Обратите внимание, что актеры не являются частью FP.

Настройка, о которой вы описываете, полагается на изменчивый контроллер, и трудно обойти ее на языке, который по умолчанию не является строгим. Однако в зависимости от того, что вы делаете, вы можете рассчитывать на фьючерсы. Например:

case Msg(info) =>
  val v1 = new Bot !! Fn1(info)
  val v2 = new Bot !! Fn2(info)
  val v3 = new Bot !! Fn3(info)
  val v4 = new Bot !! Fn4(v1(), v2(), v3())
  reply(v4())

В этом случае - поскольку !! возвращает a Future - v1, v2 и v3 будут вычисляться параллельно. Сообщение Fn4 принимает в качестве параметров применяемые фьючерсы, то есть будет ждать, пока все значения не будут вычислены до того, как они начнут вычислять.

Аналогично, ответ отправляется только после того, как v4 был вычислен, поскольку будущее также было применено.

Действительно функциональный способ сделать это - функциональное реактивное программирование или FRP для краткости. Это другая модель, чем актеры.

Красота Scala заключается в том, что вы можете комбинировать такие парадигмы в той степени, которая лучше подходит для вашей проблемы.