Оптимизация понимания Scala (карта идентичности)

Как я могу избежать map(identity) в for-пониманиях Scala?

Например, рассмотрим:

import scala.concurrent._
import scala.concurrent.duration._

object Test extends App {
  implicit val executorContext = ExecutionContext.global
  val future = Future.successful { 1 }
  val result = for (
    value <- future;
    b <- Future { value * 2 }
  ) yield b
  println(Await.result(result, 60 seconds))
}

IIUC, for-понимание переводится как что-то вроде

future.flatMap(value => Future { value * 2 }).map(identity)

Могу ли я каким-то образом избежать завершающего map(identity)? Или может/может/может ли Scala оптимизировать его? (Я полагаю, что не может, так как неясно, есть ли у map какие-либо побочные эффекты, верно?)

P.S. Я знаю, что в этом конкретном примере все можно улучшить. Меня интересует общий случай, когда, например, Future { value * 2} является вызовом f(value) функции f, возвращающей будущее.


person Hbf    schedule 25.01.2013    source источник
comment
Довольно смелое предположение, что после перевода для понимания будет .map(identity)   -  person om-nom-nom    schedule 25.01.2013
comment
Для понимания не вызывает .map(identity). просто запустите scalac -Xprint:typer, чтобы убедиться в этом.   -  person pedrofurla    schedule 25.01.2013
comment
Мне кажется, или это злоупотребление синтаксическим сахаром, когда вы можете написать что-то вроде val result = future.map( _ * 2)?   -  person Bruno Grieder    schedule 25.01.2013
comment
после scalac -Xprint:parser вы получите: (...) val result = future.flatMap(((value) => Future(value.$times(2)).map(((b) => b)))); (...) @pedrofurla, какую версию scala вы используете?   -  person Francois G    schedule 25.01.2013
comment
@BGR: я не думаю, что синтаксический сахар особенно опасен даже в принципе. И синтаксический сахар, который представляет собой понимание Scala for, чрезвычайно полезен для разъяснения исходного кода после первого или второго генератора или фильтра.   -  person Randall Schulz    schedule 25.01.2013
comment
@RandallSchulz В принципе, я согласен с вами в отношении синтаксического сахара, но понимание for/yield означает, что я хочу связать монадические операции, когда все, чего вы пытаетесь достичь в этом примере, это то, что я хочу выполнить вычисление будущего результата, который на мой взгляд лучше выражается простым map   -  person Bruno Grieder    schedule 25.01.2013
comment
@BGR: Я согласен для отдельных приложений любого из монадических HOF. Но для всех подобных выражений, кроме простейших, for сахар — замечательная вещь.   -  person Randall Schulz    schedule 25.01.2013


Ответы (1)


Это анти-шаблон для создания собственного будущего только для того, чтобы действовать аппликативно внутри него. Вместо этого вы можете:

  • future.map() и, наконец, получите результат с помощью onSuccess (это самая простая модель)
  • если вы твердо настроены на понимание, yield Future { value * 2 } а затем получите свой результат ... (хотя это не решает ложную проблему создания будущего)
  • transform свое будущее, а затем получите свой результат...
  • collect на свое будущее, а затем map(f) на результаты

В зависимости от вашего контекста и модели вычислений то или иное из этих решений может быть более подходящим: вы, кажется, представляете конкретный случай общей ситуации, но неясно, должна ли общая ситуация включать в себя итерацию по фьючерсам, цепочку преобразований в одном фьючерсе, или что-то совсем другое.

person Francois G    schedule 25.01.2013
comment
Спасибо, @huitseeker, за ваши комментарии по этому конкретному варианту использования, связанному с фьючерсами, очень полезные. Однако, как вы говорите, я пытался представить пример для общего наблюдения: а именно, что такие монадические выражения компилируются Scala в вызовы функций, где последним является map(identify). Мне интересно, можно ли это оптимизировать? Ибо в некоторых монадах последний вызов может быть дорогим. - person Hbf; 20.02.2013