Pregunta

Soy nuevo en Scala, y poder pasar las funciones a otras funciones es bastante bueno, pero ¿puedo pasar un arbitrario ¿Referencia de función a otra función? La aridad de dicho parámetro funcional se solucionará (dicho esto, también tengo curiosidad sobre si también puede aprobar una función con aridad arbitraria). Sigo tropezando con los errores de tipo. He intentado usar Any Pero no parece ayudar.

Por ejemplo, tengo el código a continuación:

class CodeRunner(val user_defined: (Int) => Unit) {
  def run(input: Int) = {
    user_defined(input)
  }
}

def arbitrary_code(input: Int) = { println("Running with input " + input) }

val d1 = new CodeRunner(arbitrary_code)

d1.run(4)

Y entiendo:

Running with input 4

Ahora, digamos que quiero pasar la siguiente función en su lugar:

def arbitrary_code(input: String) = { println("Running with input " + input) }

¿Cómo puedo cambiar mi CodeRunner clase para manejar ambos?

¿Fue útil?

Solución

Los tipos genéricos le permiten definir una clase con un tipo de marcador de posición que se especifique cuando un objeto se instancia. El compilador está contento porque puede asegurarse de que todo sea seguro, y está contento porque puede instanciar el objeto y pasar en tipos arbitrarios por el valor.

Para usar un tipo genérico con su clase, puede modificarlo así:

class CodeRunner[T] (val user_defined: (T) => Unit) {
  def run(input: T) = {
    user_defined(input)
  }
}

El [T] después de "Class CoderUnner" es la parte importante: define que hay un tipo genérico T (podría reemplazar T con otra letra capital, etc.) que se utilizará dentro de la definición de clase.

Entonces, si define un método:

def arbitrary_code(input: String) = { println("Running with input " + input) }

y luego pasarlo en:

val d1 = new CodeRunner(arbitrary_code)

... El compilador luego dice "Ajá, para este caso de CoderUnner, el tipo genérico T es una cadena". Y si invocas

d1.run("string")

El compilador estará feliz, pero no le permitirá pasar en d1.run (4).

Otros consejos

¿Cómo puedo cambiar mi CodeRunner clase para manejar ambos?

Puede hacer que el tipo arbitrario sea un parámetro de la clase:

class CodeRunner[T](val user_defined: (T) => Unit) {
  def run(input: T) = {
    user_defined(input)
  }
}

def arbitrary_code(input: Int) = { println("Running with input " + input) }

val d1 = new CodeRunner(arbitrary_code)

d1.run(4)

def arbitrary_code2(input: String) = { println("Running with input " + input) }

val d2 = new CodeRunner(arbitrary_code2)

d2.run("hello")

Tenga en cuenta que el tipo de d2 es CodeRunner[String] que no es asignable a d1 cual es CodeRunner[Int].

Para pasar una función arbitraria, ciertamente puede usar genéricos:

def run[T,U](f: T => U) = println(f)

Para la aridad arbitraria, es imposible porque una función del tipo t => u es una instancia de función1 [u, t] y una función de tipo (t, u) => v es una instancia de function2 [t, u, v]. (Además, no pude encontrar ningún caso de uso útil). Sin embargo, hay un concepto inteligente llamado "currying". Consiste en transformar una función que toma múltiples argumentos y devuelve un valor en una función que toma un solo argumento y devuelve otra función. Aquí hay un ejemplo:

def nonCurriedAdd(x: Int, y: Int) = x + y
// nonCurriedAdd(4,6)
def curriedAdd(x: Int) = (y: Int) => x + y
// we can use some syntax sugar
def curriedAdd(x: Int)(y: Int) = x + y
// curriedAdd(4)(6)

Entonces, ahora puede hacer `d1.run (curriedadd). También puede transformar una función no corredera en una curry utilizando el método "curry":

d1.run(nonCurriedAdd.curried)

¿Puedo pasar una referencia de función arbitraria a otra función? La aridad de dicho parámetro funcional se fijará

Como siempre, escriba el tipo de función que está desarrollando, y todo queda claro.

Su palabra "arbitraria" sugiere que los argumentos de la función funcionan en cualquier tipo. Es decir, son funciones polimórficas (o funciones genéricas, en algunos idiomas).

Lo siguiente debe traducirse de manera bastante limpia a Scala:

== The type of an "arbitrary" function of fixed arity
f :: a -> b -> c -> d

-- The type of a function that accepts such a
-- function as an argument, and does something with it:
g :: (a -> b -> c -> d) -> a -> b -> c -> d

-- And a function that implements something of that type
g f a b c = f a b c

Es posible que pueda encontrar algunos otros de este tipo Funciones de orden superior, que toman funciones de aridad fija, pero arbitraria (es decir, polimórfica), y operan en ellas.

Las funciones clásicas de orden superior son, por ejemplo,

map :: (a -> b) -> [a] -> [b]

fold :: (a -> b -> b) -> b -> [a] -> b

Y muchos, muchos otros.

scala> object codeRunner {
     |    def run[InputType, OutputType](code: InputType => OutputType) = (input: InputType) => code(input)
     | }
defined module codeRunner

scala> def someCode(x: Int) {
     |    println("This code uses " + x)
     | }
someCode: (x: Int)Unit

scala> def otherCode(y: String) {
     |    println("This code uses " + y)
     | }
otherCode: (y: String)Unit

scala> codeRunner.run(someCode)(10)
This code uses 10

scala> codeRunner.run(otherCode)("hello")
This code uses "hello"
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top