2017-08-04 4 views
0

関数に渡されるオブジェクトに、メソッドのコアセットを実装するよう要求する方法はありますか?関数パラメータを必要とするメソッドを実装する - Scala

たとえば、「+」演算子を実装するオブジェクトの任意の反復可能な部分を合計するsumメソッドを書くことができます。

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 

今、このメソッドは動作しますが、それは不格好だが、次のように

私の最初の実装です。もし私が何かを合計できるようにしたいのであれば、数値型と文字列に対して明示的な変換を定義するのはもちろんのこと、合計したいすべてのクラスに明示的にaddable [T]を実装する必要があります。

このように見えるように実装する方法はありますか?

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)(_+_) 

代わりに、この必要性を除去し、いくつかの設計パタパタ(私が今やっていることは事実Adapterパターンより少しのようですが)ありますか?そのようなことを行うには

+0

追加しようとしているものはなんですか? – Tyler

+1

@Tylerの代わりに – cchantep

+0

@Tylerを使用するのは、数値とベクトルの反復可能性を数学のベクトルと考える必要がありますが、同じ関数を他の場合にも使用したいので、必要なときに再利用できます。他のカスタムデータ型を合計します。 – CBlumey

答えて

1

一般的なパターンは、型クラスを使用することです。ここではhttp://typelevel.org/cats/typeclasses.html

は、ご利用の場合のAddable型クラスの実装サンプルです:ここで

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.+) 
} 

sumのサンプル実装でありますこのAddable型クラスを使用する方法、:

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

そして、いくつかの結果Uそれを歌う:

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) 
関連する問題