Question

Je suis nouveau à Scala, et d'être en mesure de transmettre des fonctions à d'autres fonctions est assez neat-- mais je peux passer un arbitraire référence de fonction à une autre fonction? L'arité dudit paramètre fonctionnel sera fixé (Cela dit, je suis aussi curieux de savoir si vous pouvez passer une fonction d'arité arbitraire ainsi). Je continue à me trébuché sur les erreurs de type. Je l'ai essayé d'utiliser Any mais il ne semble pas aider.

par exemple, je le code ci-dessous:.

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)

Et je reçois:

Running with input 4

Maintenant, disons que je veux passer la fonction suivante à la place:

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

Comment puis-je changer ma classe CodeRunner pour gérer à la fois?

Était-ce utile?

La solution

Les types génériques permettent de définir une classe avec un type d'espace réservé qui obtient spécifié quand un objet s'instancié. Le compilateur est heureux, car il peut vous assurer que tout est sûr de type, et vous êtes heureux parce que vous pouvez instancier l'objet et de passer dans les types arbitraires de la valeur.

Pour utiliser un type générique avec votre classe, vous pouvez le modifier comme ceci:

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

Le [T] après « classe CodeRunner » est la partie importante - il définit qu'il ya un type générique T (vous pouvez remplacer T par une autre lettre majuscule, etc.) qui sera utilisé dans la définition de classe <. / p>

Donc, si vous définissez une méthode:

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

et passer ensuite dans:

val d1 = new CodeRunner(arbitrary_code)

... le compilateur dit alors « aha, pour cette instance de CodeRunner T de type générique est une chaîne ». Et si vous invoquez

d1.run("string")

le compilateur sera heureux, mais ne vous laissera pas passer dans d1.run (4).

Autres conseils

Comment puis-je changer ma classe CodeRunner pour gérer à la fois?

Vous pouvez faire le type arbitraire un paramètre de la classe:

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")

Notez que le type de d2 est CodeRunner[String] qui est incessible à d1 qui est CodeRunner[Int].

Pour passer une fonction arbitraire, vous pouvez certainement utiliser les médicaments génériques:

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

arité arbitraire, il est impossible en raison d'une fonction de type T => U est par exemple de Function1 [U, T] et une fonction de type (T, U) => V est une instance de Function2 [T, U, V]. (De plus, je ne pouvais pas trouver un cas d'utilisation utile). Cependant, il existe un concept intelligent appelé « curryfication ». Elle consiste à transformer une fonction qui prend plusieurs arguments et retourner une valeur dans une fonction qui prend un seul argument et renvoie une autre fonction. Voici un exemple:

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)

Alors, vous pouvez maintenant faire `d1.run (curriedAdd). Vous pouvez également transformer une fonction non-cari dans un cari en utilisant la méthode « cari »:

d1.run(nonCurriedAdd.curried)

puis-je passer une référence de fonction arbitraire à une autre fonction? L'arité dudit paramètre fonctionnel sera fixé

Comme toujours, notez le type de la fonction que vous développez, et tout devient clair.

Votre mot « arbitraire » suggère que les arguments de la fonction de travail à tout type. C'est, ce sont des fonctions polymorphes (ou fonctions génériques, dans certaines langues).

Ce qui suit devrait se traduire assez propre à 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

Vous pourriez être en mesure de venir avec quelques autres tels fonctions d'ordre supérieur , que les fonctions de prennes de arité fixe, mais le type arbitraire (c.-à-polymorphes), et fonctionnent sur eux.

classiques fonctions d'ordre supérieur sont, par exemple de

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

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

Et beaucoup, beaucoup d'autres.

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"
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top