Часто я сталкиваюсь со следующей ситуацией: предположим, у меня есть эти три функции
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), поэтому теоретически их можно заменить результатами вычислений. Я знаю это, но компилятор не знает, поэтому он не может оптимизировать мою первую попытку. И вот мой второй вопрос:
Могу ли я как-нибудь (может быть с аннотацией) намекнуть компилятору, что моя функция ссылочно прозрачна, чтобы он мог оптимизировать эту функцию для меня (поставить там какое-то кеширование, например )?
Спасибо всем за отличные ответы! Просто невозможно выбрать один лучший ответ (может быть, потому, что все они такие хорошие), поэтому я приму ответ с наибольшим количеством голосов, я думаю, что это достаточно справедливо.