Métodos de lista de parâmetros múltiplos
Para inferência de tipo
Métodos com várias seções de parâmetro podem ser usados para auxiliar a inferência de tipo local, usando parâmetros na primeira seção para inferir argumentos de tipo que fornecerão um tipo esperado para um argumento na seção subsequente. foldLeft
na biblioteca padrão é o exemplo canônico disso.
def foldLeft[B](z: B)(op: (B, A) => B): B
List("").foldLeft(0)(_ + _.length)
Se fosse escrito como:
def foldLeft[B](z: B, op: (B, A) => B): B
Seria necessário fornecer tipos mais explícitos:
List("").foldLeft(0, (b: Int, a: String) => a + b.length)
List("").foldLeft[Int](0, _ + _.length)
Para API fluente
Outro uso para métodos de seção de vários parâmetros é criar uma API que se pareça com uma construção de linguagem. O chamador pode usar colchetes em vez de parênteses.
def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)
loop(2) {
println("hello!")
}
A aplicação de N listas de argumentos a métodos com M seções de parâmetros, onde N <M, podem ser convertidos em uma função explicitamente com a _
, ou implicitamente, com um tipo esperado de FunctionN[..]
. Este é um recurso de segurança, consulte as notas de mudança para Scala 2.0, nas Referências do Scala, para um histórico.
Funções Curried
Funções curried (ou simplesmente funções que retornam funções) podem ser aplicadas mais facilmente a N listas de argumentos.
val f = (a: Int) => (b: Int) => (c: Int) => a + b + c
val g = f(1)(2)
Esta pequena conveniência às vezes vale a pena. Observe que as funções não podem ser do tipo paramétricas, portanto, em alguns casos, um método é necessário.
Seu segundo exemplo é um híbrido: um método de seção de um parâmetro que retorna uma função.
Computação Multi Stage
Onde mais as funções curried são úteis? Aqui está um padrão que surge o tempo todo:
def v(t: Double, k: Double): Double = {
val ft = f(t)
g(ft, k)
}
v(1, 1); v(1, 2);
Como podemos compartilhar o resultado f(t)
? Uma solução comum é fornecer uma versão vetorial de v
:
def v(t: Double, ks: Seq[Double]: Seq[Double] = {
val ft = f(t)
ks map {k => g(ft, k)}
}
Feio! Envolvemos questões não relacionadas - calcular g(f(t), k)
e mapear uma sequência de ks
.
val v = { (t: Double) =>
val ft = f(t)
(k: Double) => g(ft, k)
}
val t = 1
val ks = Seq(1, 2)
val vs = ks map (v(t))
Também podemos usar um método que retorna uma função. Neste caso, é um pouco mais legível:
def v(t:Double): Double => Double = {
val ft = f(t)
(k: Double) => g(ft, k)
}
Mas se tentarmos fazer o mesmo com um método com várias seções de parâmetros, ficaremos presos:
def v(t: Double)(k: Double): Double = {
^
`-- Can't insert computation here!
}