2017-09-10 6 views
2

Ma fonction obtient une autre fonction (ce qui est le type d'entrée de mappage de type de sortie) en tant que paramètre:argument de la fonction par défaut avec les types génériques

type Handled[S,R] = S => R 

def myFunc[S,R](value: S, handled: Handled[S,R] = defaultHandled): R = { 
    handled(value) 
} 

Je dois écrire la fonction defaultHandled qui obtenir le type d'entrée et le retourner comme cela est .

Par défaut, je veux mapper le type d'entrée au type de sortie où le type d'entrée est le même que le type de sortie. Cette fonction devrait simplement passer l'entrée à la sortie pour n'importe quel type d'entrée. Comment le faire?

Répondre

5

Bien que techniquement cela est possible:

type Handled[S, R] = S => R 

def defaultHandled[S, R](x: S): R = x.asInstanceOf[R] 

def myFunc[S, R](value: S, handled: Handled[S, R] = defaultHandled[S, R] _): R = { 
    handled(value) 
} 

myFunc[Int, Int](1) 

Il est de type pas sûr et généralement pas une bonne idée. Par exemple, si vous essayez d'appeler myFunc avec des paramètres de type différents, tout en se fondant sur la valeur par défaut handled, vous obtiendrez exception d'exécution:

myFunc[Int, String](1) 

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String 

façon Scala pour répondre est d'avoir traité comme paramètre implicite . Dans ce cas, vous pouvez fournir une implémentation par défaut que le compilateur utilisera.

type Handled[S, R] = S => R 

implicit def defaultHandled[S]: Handled[S, S] = identity 

def myFunc[S, R](value: S)(implicit handled: Handled[S, R]): R = { 
    handled(value) 
} 

myFunc(1) // compiles and works 

myFunc[Int, String](1) // compilation error: Error:(11, 21) No implicit view 
         // available from Int => String. 
         //myFunc[Int, String](1) 
         //   ^
0

Si S et R sont deux types arbitraires (qui ne dépendent pas les uns des autres) alors je suppose que c'est impossible (sans cast d'exécution). Vous devez fournir defaultHandled pour chaque S, R. Et s => s est de type S => S, et non S => R pour arbitraire R.

Mais si le type Rdépend du typeS alors vous pouvez envisager de faire ce qui suit:

trait Handled[S] { 
    type R 
    def apply(s: S): R 
    } 
    object Handled { 
    type Aux[S, R0] = Handled[S] {type R = R0} 
    def apply[S, R0](f: S => R0): Aux[S, R0] = new Handled[S] { 
     override type R = R0 
     override def apply(s: S): R = f(s) 
    } 
    } 


    def myFunc[S](value: S, handled: Handled[S] = Handled[S, S](s => s)): handled.R = { 
    handled(value) 
    } 

Ici Handled[S] (au contraire à Handled.Aux[S, R]) est un existential type.

2

Je dirais que pour ce cas particulier, il y a une solution simple qui permet d'obtenir exactement le résultat souhaité: il suffit de remplacer le paramètre par défaut par une surcharge.

type Handled[S,R] = S => R 

def myFunc[S,R](value: S, handled: Handled[S,R]): R = { 
    handled(value) 
} 

def myFunc[S](value: S): S = value