2010-06-15 4 views
8

J'ai besoin d'un contrôle de retour (s'il vous plaît).Comment spécialiser un argument de type paramétré à plusieurs types différents dans Scala?

Dans un article (http://www.win-vector.com/blog/2010/06/automatic-differentiation-with-scala/) je viens d'écrire que j'ai déclaré que je crois en Scala que vous ne pouvez pas spécifier une fonction qui prend un argument qui est lui-même une fonction avec un paramètre de type non lié. J'ai modifié cette question pour essayer de simplifier l'exemple.

Le code suivant fonctionne en introduisant un trait GenericFn qui imite le trait Scala Fonction1, sauf qu'il a un paramètre de type libre dans la fonction:

object TypeExample { 
    trait NumberBase { 
     def result:String 
    } 

    class A extends NumberBase { 
     def result = "A" 
    } 

    class B extends NumberBase { 
     def result = "B" 
    } 

    trait GenericFn { 
     def apply[X<:NumberBase](x:X):String 
    } 

    def specializeAndApplyTwice(f:GenericFn):String = { 
     f[A](new A()) + f[B](new B()) 
    } 

    def main(args : Array[String]) : Unit = { 
     val f = new GenericFn { 
      def apply[X<:NumberBase](x:X):String = { x.result } 
     } 
     println(specializeAndApplyTwice(f)) 
    } 
} 

Cela fonctionne, mais est-il un moyen de le faire sans le trait GenericFn (utiliser une notation de fonction standard)? Par exemple, le code échoue ci-dessous avec l'erreur de compilation: "incompatibilité de type Trouvée: TypeExample2.A requis: _ 1 $ _ où type 1 < $: TypeExample2.NumberBase":

def specializeAndApplyTwice(f:(_<:NumberBase)=>String):String = { 
    f(new A()) + f(new B()) 
} 
+0

Votre exemple devrait probablement être: def g (f: Array [Double] => Double, x: Array [Double]): Double –

+0

... et peut-être, le second exampe doit être def g (f [Y] : Array [Y] => Y, x: Array [Y]): Y? Sinon, vous pourriez écrire def g (f: Array [_] => Double, x: Array [Double]): Double, mais je suppose que ce n'est pas ce que vous voulez. –

+0

Arjan, en fait mes exemples sont plus proches de ce que je veux. Dans mon code actuel Y a une contrainte de type (que je n'ai pas reproduite ici) de la forme Y <: NumberBase [Y] et NumberBase [Y] déclare des méthodes de conversion de et vers Y et Doubles. g() utilise cette structure pour effectuer une conversion ascendante des doublons machine en Y, travailler et ensuite convertir en double (le code extérieur ne sélectionne donc pas le type Y et n'a pas besoin de traiter le type Y). – jmount

Répondre

2

Reformuler la motivation initiale du question: Nous voulons donner un type à valeur 'g' parce que nous voulons le faire circuler. Les valeurs Scala (bien sûr) ne peuvent pas avoir de type polymorphique, même s'il s'agit de valeurs de fonction. Alors, comment donner un type dont une partie est inconnue?

Je crois donc une solution consiste à utiliser des caractères génériques (une forme d'abstraction existentielle):


    def g(f: Array[_ <: NumberBase[_]] => Double, z: Array[Double]): Double 

L'explication de la prose pour le type de g est: une fonction de Array [T] et Array [Double] à Double, où T est un certain type qui s'étend double. "un peu" est le mot qui indique l'abstraction existentielle, nous demandons qu'un tel type existe bien que nous ne nous soucions pas de ce que c'est.

+0

J'ai fortement modifié la question pour essayer de placer votre exemple. Je ne pouvais pas le faire fonctionner - mais évidemment, c'est peut-être de ma faute (je ne connais pas grand-chose aux différentes notations). – jmount

+0

Dans la question reformulée, il semble plus simple d'utiliser def specializeAndApplyTwice(f:NumberBase=>String) ... Je crois qu'il y a une difficulté supplémentaire dans la formulation originale car il fallait utiliser le paramètre type (ou le type générique _) pour construire un type de tableau. BTW pour l'exhaustivité: les fonctions des types aux valeurs sont bien connues en théorie (le calcul est appelé F-omega) mais Scala ne les a pas sous leur forme pure. Aurait besoin d'une VM appropriée. _ dans les types signifie toujours un type générique. Peut-être trouvez-vous cette page utile, elle a quelques exemples http://www.scala-lang.org/node/43 – buraq

Questions connexes