2014-04-04 17 views
16

DatoÈ possibile scrivere un tipo di funzione dipendente in Scala?

trait Foo { 
    type Bar 
} 

c'è un modo legale per scrivere qualcosa di simile f: (x: Foo) => x.Bar, in modo che il tipo di ritorno della funzione dipende l'argomento? Un esempio di utilizzo sarebbe

def compareOutput(x1: Foo, x2: Foo)(f: (x: Foo) => x.Bar /* illegal */)(comparer: (x1.Bar, x2.Bar) => Boolean) = { 
    val y1 = f(x1) 
    val y2 = f(x2) 
    comparer(y1, y2) 
} 
+0

Vedere ad esempio [come Miles Sabin utilizza i tipi di metodo dipendenti in Shapeless] (https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/syntax/hlists.scala) . –

+2

Non penso che sia rilevante. Vuole essere in grado di definire un tipo di funzione (al contrario della sola definizione di un metodo) in cui il tipo di ritorno dipende dal valore dell'argomento. Credo che questo sia al momento impossibile. Anche se riesci a definire un tipo che corrisponda all'intento di OP, non penso che potresti passare un metodo come argomento 'f' perché eta-expansion non supporta tipi di metodi dipendenti. Vedi https://issues.scala-lang.org/browse/SI-4751. Questo forzerebbe a definire quelle "funzioni dipendenti" in un modo piuttosto scomodo, come estendere un tratto personalizzato e implementare il suo metodo "apply" –

+0

@ RégisJean-Gilles: hai ragione - forse stavo leggendo troppo velocemente. Quello che descrivi potrebbe essere fatto con i valori delle funzioni polimorfiche di Shapeless, ma non con le funzioni di Scala di vaniglia. –

risposta

8

Scala non ha funzioni polimorfiche come ad esempio Haskell. Un tipo di funzione è sempre concreto. Solo i metodi possono essere polimorfici. Ciò significa, purtroppo, che il tuo tipo ipotetico (x: Foo) => x.Bar non è esprimibile in Scala.

Questo diventa evidente quando si converte metodi generici a funzioni: tutte le informazioni sul tipo è perduto:

scala> def foo[Bar](x: Bar): Bar = ??? 
foo: [Bar](x: Bar)Bar 

scala> foo _ 
res1: Nothing => Nothing = <function1> 

Si potrebbe avere anche notato che scala non riescono a convertire i metodi con i tipi dipendenti alle funzioni. Ecco perché è impossibile soddisfare il vostro tipo ipotetico:

scala> def foo(x: Foo): x.Bar = ??? 
foo: (x: Foo)x.Bar 

scala> foo _ 
<console>:10 error: method with dependent type (x: Foo)x.Bar cannot be converted 
        to function value. 

vedono anche this e this domande.


Esistono tuttavia diverse soluzioni al problema. Uno sarebbe per incapsulare il metodo dipendente digitato in un tratto aiutante:

trait FooFunc { 
    def apply(x: Foo): x.Bar 
} 

def compareOutput(x1: Foo, x2: Foo)(f: FooFunc)(comparer: ...) = { 
    val y1 = f(x1) 
    val y2 = f(x2) 
    comparer(y1,y2) 
} 

È quindi possibile creare istanze di FooFunc che è possibile passare nel vostro metodo di compareOutput.

Problemi correlati