Sto lavorando su una piccola libreria per i modelli economici che controllano le unità delle entità, utilizzando i tipi, ad es. invece di val apples = 2.0
scriviamo val apples = GoodsAmount[KG, Apples](2.0)
. Per creare un pacchetto di merci, provo a usare le liste HL dalla libreria senza forma. Funziona bene, ma in alcuni casi non posso essere un codice generico come preferisco. Vedi per es. il seguente problemaSenza forma: controllo dei vincoli di tipo delle funzioni polimorfiche
Inizio con un semplice codice che spiega quello che voglio sollevare in informe. Creiamo due classi, che rappresentano Km, le altre miglia. Dovrebbe essere consentito aggiungere classi Km, ma non miglia. Che io usi un tipo astratto T è principalmente motivato dalla nostra libreria più complessa. E la chiamata indiretta alla funzione '+' è solo perché abbiamo bisogno di qualcosa di simile nel caso senza forma dietro.
trait Foo {
type T
val v: Double
def +[B <: Foo](other: B)(implicit ev: this.T =:= other.T) = v + other.v
}
trait _Km
trait _Miles
case class Km(v: Double) extends Foo { type T = _Km }
case class Miles(v: Double) extends Foo { type T = _Miles }
object ExampleSimple extends App {
def add[A <: Foo, B <: Foo](a: A, b: B)(implicit ev: a.T =:= b.T) = { a + b }
add(Km(1), Km(2))
// add(Km(1), Miles(2)) /* does not compile as intended */
}
Questo funziona come previsto. Ma è necessario avere il controllo di tipo Contraint sulla funzione 'aggiungi'. Il mio tentativo di estendere questo per HLists assomiglia a questo:
object ExampleShapeless extends App {
import shapeless._
val l1 = Km(1) :: Km(2) :: HNil
val l2 = Km(4) :: Km(3) :: HNil
object add extends Poly1 {
implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a, b) => a + b }
}
(l1 zip l2).map(add)
}
Ma questo genera il seguente messaggio di errore (utilizzando Scala 2.10.2):
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:50: Cannot prove that a.T =:= b.T.
[error] implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a: Foo, b) => a + b }
[error] ^
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:54: could not find implicit value for parameter mapper: shapeless.Mapper[ExampleShapeless.add.type,shapeless.::[(Km, Km),shapeless.::[(Km, Km),shapeless.HNil]]]
[error] (l1 zip l2).map(add)
Il primo errore deve essere fissato, nel caso che potrei aggiungere un Type Constraint alla funzione caseTuple, ma per essere onesti, non ho capito come funziona la funzione at e dove potrei aggiungere il parametro evidence implicito. E anche io non so, cosa devo fare, in modo che il Mapper trovi il suo valore implicito.
Una versione meno generico, dove ho replase la funzione caseTuple con
implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b }
funziona bene, ma avrebbe bisogno di scrivere un sacco di codice ridondante (ok, questa soluzione sarebbe ancora meglio come la nostra soluzione corrente utilizzando tuple). Qualcuno può darmi un suggerimento su come posso risolvere questo problema?
Grazie, Klinke
Si potrebbe provare a definire il proprio 'Foo' in questo modo:' trait Foo [T <: Foo] {v: Double; + (t T): T = ...} '. 'classe Km (val v: Double) estende Foo [Km]'. 'implicit def add [T] = at [(Foo [T], Foo [T])]' – senia