2012-05-13 13 views
6

I (nazik kullanıcı soc benim için formüle) aşağıdaki genel aralığı sınıfı vardır:Scala örtülü Sayısal [T] tamamlayıcı nesnesinde

case class Interval[T](from: T, to: T)(implicit num: Numeric[T]) { 
    import num.mkNumericOps // allows us to write from.toDouble and to.toDouble 
    def mid: Double = (from.toDouble + to.toDouble)/2.0 
} 

Tipik kullanım durumları: [Çift] aralığı veya zaman aralığına [Uluslararası].

object Interval { 

    def union[T](interval1: Interval[T], interval2: Interval[T])(implicit num: Numeric[T]) = { 
    import num.mkOrderingOps // allows interval1.from min 
    Interval[T](interval1.from min interval2.from, interval1.to max interval2.to) 
    } 

    def intersect[T](interval1: Interval[T], interval2: Interval[T])(implicit num: Numeric[T]) = { 
    import num.mkOrderingOps 
    Interval[T](interval1.from max interval2.from, interval1.to min interval2.to) 
    } 

} 

Her iki yöntemleri içinde (implicit num: Numeric[T]) ve import num.mkOrderingOps kopyalamak için çirkin demirbaş var: İkili birliği ve kavşak operatörleri eklemek için ben refakatçi nesnesinde (implicit num: Numeric[T]) ile benzer bir seyir izledi. Bunu, Interval nesnesinin kendisinin seviyesinde, sadece bir kez yapmanın bir yolu var mı?

cevap

8

Evet var.

İlk önce içe aktarma. Bunun yerine Interval kapsamında Ordering.Implicits._ alabilirsiniz. operasyon şeyin olduğu bu implicits ile

object Interval { 
    import Ordering.Implicits._ 

    def union[T](....)(implicit num: Numeric[T]) = { 
    // do not import num.mkOrderingOps 
    ... 
    } 
    ... 
} 

, bir sipariş işlemi bulduğunda, bu kapsamda (Sayısal bir sipariş olduğunu) örtük Sipariş için bakacağız. Ve rutinlerin her birinde kapsam içinde uygun bir örtük var. Aritmetik işlemlere de ihtiyacınız varsa, ayrıca, örtülü bağımsız değişkenle birlikte Numeric.Implicits._

öğelerini de içe aktarın.Eğer def f[T: X](args) yerine def f[T](args)(implicit someName: X[T])

fark yazabilir sen (bağlı bağlam ile örtülü bir isim yapabilirsiniz yok yani: gitmekte olan bir bağlamı denir bunun için dil, bir kısayol vardır implictly [T] kullanın ama sonra bu pek kısadır. Neyse ki, ithalat Ordering.Implicits._ Yani

Ayrıca

object Interval { 
    import Ordering.Implicits._ 
    // also import Numeric.Implicits._ if you need +,-,*,/ ... 
    def union[T: Numeric] ... 
    def intersection[T: Numeric] ... 
} 
+0

Teşekkür ederim. Güzel kıskançlık. Bu bağlamla ilgili fikri hiç görmedim. Kim böyle şeyleri öğrenir? Scala'da bir kitap okudum ama bağlam sınırlarını hatırlamıyorum. –

+0

Örneğin bkz. [Scala'da bağlamsal bağ nedir?] (Http://stackoverflow.com/questions/2982276/what-is-a-context-bound-in-scala). – Jesper

5

Numeric tür sınıfının Interval türündeki nesnesi, kapsam kapsamında bir yere bağlı olması gereken T tür parametresine sahiptir. Benzersiz bir sabit değer olan Interval, bu bağlamayı sağlayamaz. Bu özel sorunun

bir çözüm onlar T bağlanmasının ve ilişkili Numeric örneği paylaşmak istiyorum bu durumda Intervalsınıf sıradan örnek yöntemlerde, içine union ve intersect operasyonların tanımları taşımak olacaktır

case class Interval[T : Numeric](from: T, to: T) { 
    import Numeric.Implicits._ 
    import Ordering.Implicits._ 

    def mid: Double = (from.toDouble + to.toDouble)/2.0 
    def union(interval2: Interval[T]) = 
    Interval(this.from min interval2.from, this.to max interval2.to) 
    def intersect(interval2: Interval[T]) = 
    Interval(this.from max interval2.from, this.to min interval2.to) 
} 

Ancak, bu operasyonların tanımlarını tutmayı tercih ederse

ayırmak Interval sınıf, bir yaklaşımdan sen throug kovalamak gerekir örtük Demirbaş miktarını azaltmaya sınıfın geri kalanı, API'leriniz kendi üst düzey tip sınıflarınızı Sayısal [T] olarak tanımlamaktır. Örneğin,
// Type class supplying union and intersection operations for values 
// of type Interval[T] 
class IntervalOps[T : Numeric] { 
    import Ordering.Implicits._ 

    def union(interval1: Interval[T], interval2: Interval[T]) = 
    Interval[T](interval1.from min interval2.from, interval1.to max interval2.to) 

    def intersect(interval1: Interval[T], interval2: Interval[T]) = 
    Interval[T](interval1.from max interval2.from, interval1.to min interval2.to) 
} 

implicit def mkIntervalOps[T : Numeric] = new IntervalOps[T] 

def use[T](i1 : Interval[T], i2 : Interval[T])(implicit ops : IntervalOps[T]) = { 
    import ops._ 
    val i3 = union(i1, i2) 
    val i4 = intersect(i1, i2) 
    (i3, i4) 
} 

Üçüncü seçenek

ek yöntemlerle orijinal sınıfını zenginleştirmek örtük tanımını kullanarak bu iki birleştirmektedir gibi görünecektir kullanımda olan

class IntervalOps[T : Numeric](interval1 : Interval[T]) { 
    import Ordering.Implicits._ 

    def union(interval2: Interval[T]) = 
    Interval[T](interval1.from min interval2.from, interval1.to max interval2.to) 

    def intersect(interval2: Interval[T]) = 
    Interval[T](interval1.from max interval2.from, interval1.to min interval2.to) 
} 

implicit def enrichInterval[T : Numeric](interval1 : Interval[T]) = 
    new IntervalOps[T](interval1) 

type Ops[T] = Interval[T] => IntervalOps[T] 

Daha sonra kullanımda,

def use[T](i1 : Interval[T], i2 : Interval[T])(implicit ops : Ops[T]) = { 
    val i3 = i1 union i2 
    val i4 = i1 intersect i2 
    (i3, i4) 
} 
+0

ile artık bir isim gerekmez, compainon nesne 'Interval' bir güzel örtülü dönüşümler koymak için bir yer.O zaman, 'use' yöntemi ile son örnekte sadece yanlısı vide 'Sayısal 'bağlam sınırları' [T: Sayısal] (i1: Aralık [T], i2: Aralık [T])' – 4e6

+0

Teşekkürler Miles. Değirmenim için çok cesurca! –