2012-02-12 15 views
7

Quali tecniche posso utilizzare in Scala per gestire elenchi di parametri di tipo lungo?Scala: come lavorare con elenchi di parametri di tipo lungo

Sto lavorando su un piccolo framework per l'esecuzione di vari tipi di giochi con diversi ambienti simulati. Sto cercando di mantenere alcune parti del framework relativamente generiche, quindi sto introducendo vari tipi come parametri di tipo, come lo stato dell'ambiente, il risultato del gioco, ecc.

Funziona tutto abbastanza bene e lo faccio ottenere i benefici desiderati da un framework sicuro per il tipo ma generico. Ma le firme di tipo sono cresciute al punto da rendere il codice piuttosto difficile da leggere e il refactoring è diventato piuttosto ingombrante. La firma del simulatore di livello superiore ha otto parametri di tipo e molti dei tipi principali hanno da tre a cinque. Errori del tipo di compilatore individuali, dal momento che elencano i tipi di parametri di classe o funzione (che naturalmente sono anche parametrizzati in base al tipo) sembrano eseguire regolarmente un centinaio di righe.

Occasionalmente, ma molto raramente, posso omettere i parametri del tipo, ad es. su costruttori. Ma nella maggior parte dei casi almeno uno dei tipi non viene dedotto, quindi finisco per dover inserire l'intero tipo di firma.

Ovviamente questo non è l'ideale e sto cercando modi per risolvere questo problema. Tutto il consiglio sarebbe apprezzato!

+6

poche linee di codice di esempio sono sempre apprezzati;) – agilesteel

+0

È un problema molto generale. Non sono sicuro che il codice di esempio aggiungerebbe molto valore. Sono solo le solite cose: tratti, classi, funzioni, ognuno con parametri di tipo, campi/membri anche con parametri di tipo. –

risposta

8

Considerare il caso in cui si dispone di un gruppo di parametri di tipo strettamente correlati; li passi insieme come argomenti tipo. In questo esempio, questo gruppo è A e B.

trait X[A, B, C] { 
    new Y[A, B, Int] {} 
} 

trait Y[A, B, D] { 
    def a: A = sys.error("") 
} 

è possibile comprimere questi due tipi in un singolo parametro di tipo con membri del tipo tipo alias contenenti:

type AB = { type A; type B } 
trait Y[ab <: AB, D] { 
    def a: ab#A = sys.error("") 
} 
trait X[ab <: AB, C] { 
    new Y[ab, C] {} 
} 
new X[{ type A=Int; type B=Int}, String] {} 
+0

Oooh, è pulito! Lo proverò appena possibile! –

+0

Hai anche la possibilità di utilizzare la varianza con questo approccio. – retronym

+1

Come si specifica la varianza? Nel tuo esempio, ad es. se Y era originariamente tratto Y [+ A, -B]? –

10

Due soluzioni vengono in mente.

  1. Utilizzare alias tipo.

    scala> class Foo[A, B, C, D, E] 
    defined class Foo 
    
    scala> type Bar[A] = Foo[A, Int, Int, Int, Float] 
    defined type alias Bar 
    
    scala> new Bar[String] 
    res23: Foo[String,Int,Int,Int,Float] = [email protected] 
    
  2. Uso abstract type members invece di parametri di tipo.

    scala> class Bar { 
        | type A 
        | type B <: AnyVal 
        | type C 
        | } 
    defined class Bar 
    
    scala> new Bar { 
        | type A = String 
        | type B = Int 
        | type C = Int 
        | } 
    res24: Bar{type A = String; type B = Int; type C = Int} = [email protected] 
    
    scala> trait Baz { 
        | type A = String 
        | } 
    defined trait Baz 
    
    scala> new Bar with Baz { 
        | type B = Int 
        | type C = String 
        | } 
    res25: Bar with Baz{type B = Int; type C = String} = [email protected] 
    
    scala> null.asInstanceOf[res25.A] 
    res26: res25.A = null 
    
    scala> implicitly[res25.A =:= String] 
    res27: =:=[res25.A,String] = <function1> 
    

Si potrebbe desiderare di condividere un codice con noi in modo che possiamo dare alcuni consigli più specifici.

+0

La prima risposta che uso già; sarebbe ancora più bello se in qualche modo potessi usare l'alias di tipo definito per accedere al costruttore del tipo sottostante. Il secondo è interessante; Lo esplorerò. –

Problemi correlati