Domanda

Sono stato nei guai con la Scala 2.8 per divertirsi e cercare di definire un magnaccia che aggiunge un "come" metodo per digitare costruttori, consentendo di convertire da un funtore ad un altro (si prega di trascurare il fatto che io non sono necessariamente trattare con functors qui). Così, per esempio, si potrebbe usare in questo modo:

val array:Array[T]
val list:List[T] = array.as[List]

Quindi, ecco quello che ho cercato di fare:

object Test {
    abstract class NatTrans[F[_], G[_]] {
        def convert[T](f:F[T]):G[T]
    }

    implicit def array2List:NatTrans[Array, List] = new NatTrans[Array, List] { 
        def convert[T](a:Array[T]) = a.toList
    }

    // this next part gets flagged with an error
    implicit def naturalTransformations[T, F[_]](f:F[T]) = new {
        def as[G[_]](implicit n:NatTrans[F, G]) = n convert f
    }
}

tuttavia la definizione di naturalTransformations è contrassegnato con errore "non può esistenzialmente astratto su tipo parametrico G [T]" . Per risolvere questo problema, posso riscrivere naturalTransformations insieme ad un Transformable classe aggiuntiva in questo modo:

class Transformable[T, F[_]](f:F[T]) {
    def as[G[_]](implicit n:NatTrans[F, G]) = n convert f
}

implicit def naturalTransformations[T, F[_]](f:F[T]) = new Transformable[T, F](f)

e sembra funzionare. Ma sembra che il mio primo tentativo dovuto essere equivalente, quindi sono curioso di sapere perchè non è riuscito e quali i mezzi messaggio di errore.

È stato utile?

Soluzione

La mia impressione sarebbe che questo è perché a causa delle seguenti dichiarazioni in spec, § 6.11, blocchi:

  

Un tipo definito localmente tipo definizione t = T è vincolata dalla clausola esistenziale   tipo T>: T <: T. È un errore se t trasporta parametri di tipo.

E un'espressione creazione dell'istanza strutturale è valutata ad un blocco, così


new {def greet{println("hello")}}

è un'abbreviazione per


{ class anon$X extends AnyRef{ def greet = println("hello") }; new anon$X }

quindi restituisce un'espressione blocco (secondo § 6.10 della specifica), con la suddetta restrizione. Perché questa restrizione è lì non lo so, però. L'errore che viene generato può essere trovato nella classe TYPERS all'indirizzo questa posizione , che sembra confermare che questa restrizione è la causa dell'errore che si vede. Come lei ha ricordato, che codifica per la funzione in una classe di rimuovere la restrizione dell'espressione di blocco:


scala> class N[M[_]]
defined class N

scala> class Q { def as[M[_]](n:N[M]) = null}
defined class Q

scala> new { def as[M[_]](n:N[M]) = null}       
:7: error: can't existentially abstract over parameterized type M
       new { def as[M[_]](n:N[M]) = null}

Altri suggerimenti

Per me questo suona come una semplicità contro caso generalità: ci potrebbe essere una nuova variabile di tipo generato ogni volta che un blocco è stato creato catturando un certo tipo costruttore di un'istanza di tipo esistenziale, ma che renderebbe la diagnostica degli errori più difficile da capire.

Si noti inoltre che avere una classe trasforma la chiamata in un'INVOKEVIRTUAL veloce, anziché invocare come () metodo per riflessione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top