2017-08-04 3 views
0

Existe-t-il un moyen de demander aux objets transmis à une fonction de mettre en œuvre un ensemble de méthodes de base? Par exemple, j'aimerais pouvoir écrire une méthode sum pour sommer n'importe quel itérable des objets qui implémentent l'opérateur '+'.Exiger les paramètres de fonction Méthode d'implémentation - Scala

Ma mise en œuvre initiale est la suivante

trait addable[T <: addable[T]]{ 
    def +(other: T): T 
} 

def sum[T <: addable[T]](items: Iterable[T]) = 
    if(items.isEmpty) throw new Exception("Can't sum nothing") 
    else items.tail.foldRight(items.head)(_+_) 
      //Starst with the first element and adds all other elements to it 

Maintenant, cette méthode fonctionne, mais il est maladroit. Si je veux que quelque chose soit sommable, je dois implémenter explicitement [T] dans chaque classe que je veux additionner, sans parler de définir un tas de conversions explicites pour les types numériques et les chaînes.

Existe-t-il un moyen de l'implémenter pour qu'il ressemble à ceci?

def sum[T fulfills addable[T]](items: Iterable[T]) = 
    if(items.isEmpty) throw new Exception("Can't sum nothing") 
    else items.tail.foldRight(items.head)(_+_) 

Sinon, est-il un bagout de conception qui élimine la nécessité de ce (ce que je fais en ce moment semble effectivement être un peu plus que le motif de l'adaptateur)?

+0

Quels types de choses essayez-vous d'ajouter? – Tyler

+1

J'utiliserais plutôt typeclassing – cchantep

+0

@Tyler, j'ai actuellement besoin d'ajouter juste des nombres et des itérables de nombres (pensez à des vecteurs mathématiques), mais je voudrais avoir la même fonction pour d'autres cas ainsi il peut être réutilisé quand j'ai besoin additionne un autre type de données personnalisé. – CBlumey

Répondre

1

Un modèle commun pour faire une telle chose est d'utiliser classes de types: http://typelevel.org/cats/typeclasses.html

Voici un exemple d'implémentation de Addable classe de types pour votre cas d'utilisation:

trait Addable[T] { 
    def +(a: T, b: T): T 
} 

// Among other places Scala searches for implicits 
// in the companion objects of the relevant classes. 
// Read more in this answer: https://stackoverflow.com/a/5598107 
object Addable { 

    // Using context bound notation 
    def apply[T : Addable]: Addable[T] = implicitly 

    // Instance of Addable typeclass for types, 
    // that have an instance of the built-in Numeric typeclass 
    implicit def numeric[T : Numeric]: Addable[T] = { 
    import Numeric.Implicits._ 
    // This uses Scala 2.12 feature of automatic convertions of lambdas to SAMs 
    // You can create an instance of an anonymous subclass in older versions. 
    _ + _ 
    } 

    // Instance of Addable for all kinds of Iterables, 
    // that adds them element by element (like mathematical vectors) 
    implicit def iterable[That, T](implicit 
    ev: That <:< IterableLike[T, That], // To compute the element type T from That 
    cbf: CanBuildFrom[That, T, That], // To call `map` method 
    add: Addable[T]      // To add elements of the iterable 
): Addable[That] = 
    (a, b) => (a, b).zipped.map(add.+) 
} 

Voici un exemple d'implémentation du sum méthode, qui utilise cette Addable classe de types:

def sum[T : Addable](items: Iterable[T]): T = items. 
    reduceOption(Addable[T].+). 
    getOrElse(throw new Exception("Can't sum nothing")) 

Et certains résultats u chantez:

scala> sum(Seq(1.2, 3.4, 5.6)) 
res0: Double = 10.2 

scala> sum(Seq(Vector(1,2), Vector(4,5), Vector(6,7))) 
res1: scala.collection.immutable.Vector[Int] = Vector(11, 14)