Scala Literales Funcionales con Implicitos


Perdóname si esto ya se ha preguntado en otro lugar. Tengo una pregunta de sintaxis de Scala que involucra valores de función y parámetros implícitos.

Me siento cómodo usando implicits con la función currying de Scala. Por ejemplo, si tuviera una función sum y quisiera hacer que el segundo argumento sea implícito:

scala> def sum(a: Int)(implicit b: Int) = a + b
sum: (a: Int)(implicit b: Int)Int

¿Hay alguna forma de hacer esto usando la sintaxis function-value? Ignorando lo implícito por un momento, normalmente escribo valores de función curry como esto:

scala> val sum2 = (a: Int) => (b: Int) => a + b
sum: (Int) => (Int) => Int = <function1>

Sin embargo, la firma de la función en el segundo enfoque es muy diferente (el currying se expresa explícitamente). Simplemente agregar la palabra clave implícita a b no tiene mucho sentido y el compilador también se queja:

scala> val sum2 = (a: Int) => (implicit b: Int) => a + b
<console>:1: error: '=>' expected but ')' found.
       val sum2 = (a: Int) => (implicit b: Int) => a + b
                                              ^

Además, la aplicación parcial de la suma desde el primer enfoque para obtener un valor de función también causa problemas:

scala> val sumFunction = sum _
<console>:14: error: could not find implicit value for parameter b: Int
       val sumFunction = sum _
                         ^

Esto me lleva a creer que las funciones que tienen parámetros implícitos deben tener dichos parámetros determinados cuando se crea el valor-función, no cuando el valor-función se aplica más adelante. Es este realmente el caso? ¿Puede usar un parámetro implícito con un valor de función?

Gracias por la ayuda!

Author: shj, 2011-06-13

3 answers

scala>  val sum2 = (a: Int) => {implicit b: Int => a + b}
sum2: (Int) => (Int) => Int = <function1>

Esto hará que b sea un valor implícito para el ámbito del cuerpo de la función, por lo que puede llamar a métodos que esperan un Int implícito.

No creo que pueda tener argumentos implícitos para las funciones, ya que entonces no está claro qué es la función. Es Int => Int o () => Int?

Lo más cercano que encontré es:

scala> case class Foo(implicit b: Int) extends (Int => Int) {def apply(a: Int) = a + b}
defined class Foo

scala> implicit val b = 3
b: Int = 3

scala> Foo()
res22: Foo = <function1>

scala> res22(2)
res23: Int = 5
 16
Author: IttayD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-13 03:24:04

En este fragmento

scala> val sum2 = (a: Int) => (b: Int) => a + b
sum: (Int) => (Int) => Int = <function1>

Tenga en cuenta que el tipo preciso de sum2 es Function1[Int, Function1[Int, Int]]. También podría escribirse como

val sum2 = new Function1[Int, Function1[Int, Int]] {
    def apply(a: Int) = new Function1[Int, Int] {
        def apply(b: Int) = a + b
    }
}

Ahora, si tratas de hacer b implícito, obtienes esto:

scala>     val sum2 = new Function1[Int, Function1[Int, Int]] {
     |         def apply(a: Int) = new Function1[Int, Int] {
     |             def apply(implicit b: Int) = a + b
     |         }
     |     }
<console>:8: error: object creation impossible, since method apply in trait Function1 of type (v1: Int)Int is not defined
               def apply(a: Int) = new Function1[Int, Int] {
                                       ^

O, en otras palabras, las interfaces de Function no tienen parámetros implícitos, por lo que cualquier cosa con un parámetro implícito no es un Function.

 9
Author: Daniel C. Sobral,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-20 13:16:05

Intente sobrecargar el método apply.

scala> val sum = new Function1[Int, Function1[Int, Int]] {
         |      def apply(a: Int) = (b: Int) => a + b
         |      def apply(a: Int)(implicit b: Int) = a + b
         |}
sum: java.lang.Object with (Int) => (Int) => Int{def apply(a:Int)(implicit b: Int): Int} = <function1>

scala> sum(2)(3)
res0: Int = 5

scala> implicit val b = 10
b: Int = 10

scala> sum(2)
res1: Int = 12
 3
Author: agilesteel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-14 15:12:58