эквивалент Clojure 'let' в Scala

Часто я сталкиваюсь со следующей ситуацией: предположим, у меня есть эти три функции

def firstFn: Int = ...
def secondFn(b: Int): Long = ...
def thirdFn(x: Int, y: Long, z: Long): Long = ...

, и у меня также есть вычислить функцию . Мой первый подход может выглядеть так:

def calculate(a: Long) = thirdFn(firstFn, secondFn(firstFn), secondFn(firstFn) + a)

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

def calculate(a: Long) = {
  val first = firstFn
  val second = secondFn(first)

  thirdFn(first, second, second + a)
}

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

Итак, моя цель здесь - определить функцию calculate с одним выражением . Я придумал 2 решения.

1 - С помощью scalaz я могу определить это так (есть ли лучшие способы сделать это с помощью scalaz?):

  def calculate(a: Long) = 
    firstFn |> {first => secondFn(first) |> {second => thirdFn(first, second, second + a)}}

Что я не делаю ' В этом решении нравится то, что оно вложено. Чем больше у меня val s, тем глубже это вложение.

2 - С для понимания я могу добиться чего-то похожего:

  def calculate(a: Long) = 
    for (first <- Option(firstFn); second <- Option(secondFn(first))) yield thirdFn(first, second, second + a)

С одной стороны, это решение имеет плоскую структуру, так же, как let в Clojure, но, с другой стороны, мне нужно обернуть результаты функций в Option и получить Option как результат из calculate ] (хорошо, что я имею дело с нулями, но я не ... и не хочу)

Есть ли более эффективные способы достижения моей цели? Каков идиоматический способ решения таких ситуаций (может быть, я должен остаться с val s ... но пусть способ сделать это выглядит так элегантно)?

Из других передать это ' s подключен к Ссылочная прозрачность . Все три функции ссылочно прозрачны (в моем примере firstFn вычисляет некоторую константу, например Pi), поэтому теоретически их можно заменить результатами вычислений. Я знаю это, но компилятор не знает, поэтому он не может оптимизировать мою первую попытку. И вот мой второй вопрос:

Могу ли я как-нибудь (может быть с аннотацией) намекнуть компилятору, что моя функция ссылочно прозрачна, чтобы он мог оптимизировать эту функцию для меня (поставить там какое-то кеширование, например )?

Edit

Спасибо всем за отличные ответы! Просто невозможно выбрать один лучший ответ (может быть, потому, что все они такие хорошие), поэтому я приму ответ с наибольшим количеством голосов, я думаю, что это достаточно справедливо.

22
задан tenshi 4 February 2011 в 18:55
поделиться