O equivalente 'let' de Clojure em Scala
Muitas vezes, enfrento a seguinte situação: suponha que tenho essas três funções
def firstFn: Int = ...
def secondFn(b: Int): Long = ...
def thirdFn(x: Int, y: Long, z: Long): Long = ...
e eu também tenhocalculate
função. Minha primeira abordagem pode ser assim:
def calculate(a: Long) = thirdFn(firstFn, secondFn(firstFn), secondFn(firstFn) + a)
Parece bonito e sem colchetes - apenas uma expressão. Mas como não é o ideal, acabo com este código:
def calculate(a: Long) = {
val first = firstFn
val second = secondFn(first)
thirdFn(first, second, second + a)
}
Agora são várias expressões cercadas por colchetes. Nesses momentos, invejo Clojure um pouco. Comdeixe funcionar Eu posso definir esta função em uma expressão.
Então, meu objetivo aqui é definircalculate
função com uma expressão. Eu venho com 2 soluções.
1 - Comscalaz Posso defini-lo assim (existem melhores maneiras de fazer isso com o scalaz?):
def calculate(a: Long) =
firstFn |> {first => secondFn(first) |> {second => thirdFn(first, second, second + a)}}
O que eu não gosto nessa solução é que ela está aninhada. O maisval
s Eu tenho mais profundo esse aninhamento.
2 - Comfor
compreensão eu posso conseguir algo semelhante:
def calculate(a: Long) =
for (first <- Option(firstFn); second <- Option(secondFn(first))) yield thirdFn(first, second, second + a)
Por um lado, esta solução tem estrutura plana, assim comolet
no Clojure, mas por outro lado, preciso agrupar os resultados das funções emOption
e receberOption
como resultado decalculate
(é bom que eu esteja lidando com nulos, mas eu não ... e não quero).
Existem melhores maneiras de alcançar meu objetivo? Qual é o caminho idiomático para lidar com essas situações (talvez eu deva ficar comval
s ... maslet
maneira de fazê-lo parece tão elegante)?
Por outro lado, está conectado aTransparência referencial. Todas as três funções são referencialmente transparentes (no meu exemplofirstFn
calcula alguma constante como Pi); portanto, teoricamente, elas podem ser substituídas pelos resultados do cálculo. Eu sei disso, mas o compilador não, por isso não pode otimizar minha primeira tentativa. E aqui está minha segunda pergunta:
De alguma maneira (posso estar com anotação), posso dar uma dica ao compilador, que minha função é referencialmente transparente, para que ele possa otimizar essa função para mim (coloque algum tipo de cache lá, por exemplo)?
EditarObrigado a todos pelas ótimas respostas! É simplesmente impossível selecionar uma melhor resposta (pode ser porque todas são boas), por isso aceitarei a resposta com mais votos positivos, acho que é justo o suficiente.