2013-09-01 34 views
5

Scala'da f-sınırlı polimorfizm elde etmek için soyut tiplerin kullanılması gerektiğini ifade eden birkaç makale okudum. Bu, öncelikle tür çıkarım sorunlarını hafifletmek, ancak aynı zamanda, özyinelemeli türleri tanımlarken tür parametrelerinin ortaya çıkardığı karesel büyümeyi de ortadan kaldırmaktır. Scala'da soyut tipli F-sınırlı polimorfizm

Bu

çok şekilde tanımlanmıştır:

1), bir kullanıcı, bu tür bir nesne referans istediği her zaman, aynı zamanda eder:

trait EventSourced[E] { 
    self => 

    type FBound <: EventSourced[E] { type FBound <: self.FBound } 

    def apply(event: E): FBound 
} 

Bununla birlikte, bu iki konu tanıtmak görünür FBound tip parametresi.

def mapToSomething[ES <: EventSourced[E], E](eventSourced: ES#FBound): Something[ES, E] = ... 

2) derleyici iletisiyle başarısız, yukarıdaki gibi yöntemler için tip parametrelerini anlaması için artık edemiyor:

Type mismatch, expected: NotInferredES#FBound, actual: MyImpl#FBound 

orada herkes bir kullanan var mı bu bir kod koku gibi hissediyor F-sınırlı polimorfizmin çözümlerinde başarılı bir şekilde uygulanması, derleyicinin hala türlerini çıkarabilmesi mümkün müdür?

+0

Scala koleksiyonları kütüphane https://github.com/ljwagerfield/scala-type-inference/blob/master/README.md#avoiding-f-bounded-polymorphism sorunsuz başarıyla polimorfizm F-sınırlanmış kullanır. Tip üyeleri yerine tip parametrelerini kullanır, buna dayalı bir çözüm denemek isteyebilirsiniz. – wingedsubmariner

+0

Lütfen bana bakmak için bir örnek verebilir misiniz, yani kütüphanenin hangi bölümleri bunu yapıyor? –

+0

Standart kitaplıktaki [Liste] 'ye (http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List) bakın. GenericTraversableTemplate ve LinearSeqOptimized öğelerinin kalıtımında kullanılan F sınırlı polimorfizme dikkat edin. – wingedsubmariner

cevap

3

f-sınırlanmış polimorfizmi çoğu durumda kaçınılmalıdır fark beri ettik - daha doğrusu - tercih gerektiğini alternatif bir tasarımı genellikle var. Bunu önlemek için nasıl çalıştığını anlamak için, öncelikle bize bunu gerektirir kılan bilmek gerekir: Bir tür önemli arayüz türetilmiş türlerinde tanıtılacak dönüşür beklediği zaman

F-sınırlanmış polimorfizmi ortaya çıkar.

Bu yerine miras yoluyla onlara destek teşebbüs değişimin beklenen alanlarını oluşturan tarafından önlenir.

: (Gang of Four, 1995) Örneğin

- 'sınıf miras'

üzerinde

Favor 'nesne kompozisyonu': Bu aslında geri dört tasarım desenleri Gang geliyor

trait Vehicle[V <: Vehicle[V, W], W] { 
    def replaceWheels(wheels: W): V 
} 

olur:

trait Vehicle[T, W] { 
    val vehicleType: T 
    def replaceWheels(wheels: W): Vehicle[T, W] 
} 

Burada, 'beklenen değişiklik' araç tipidir (ör. Bike, Car, Lorry). Bir önceki örnekte, bunun, Araç kullanılarak herhangi bir işlev için W çıkarımını olanaksız kılan, sınırlı bir tür gerektiren, kalıtım yoluyla ekleneceği varsayılmıştır. Kompozisyon kullanan yeni yöntem, bu problemi sergilemez.

Bkz:

+0

> Bileşimi kullanan yeni yöntem bu sorunu göstermiyor Tam olarak doğru değil. Tip seviyesi kontrolleri korumak istiyorsanız, en sonunda 'VehicleType [V <: VehicleType] 'gibi ihtiyacınız olacaktır. – ayvango

-1
+0

Bu örnek, tip parametrelerini kullanır ve bu nedenle çıkarım sorunlarına neden olur. Örneğimde, şu yöntem tanımı için türler çağrı sitesinde çıkarılamaz: def doSomething [ES <: EventSourced [ES, E], E] (şu: ES) –

+0

Twitter veya Scala kitaplığındaki örneklerde F-bağlı tip parametresi, sınıfın kendisi değil, yöntemlerdir. F-sınırlı polimorfizm, metotların, bu türün türüne, alt sınıflarda yer alan kesin tipe atıfta bulunmasına izin verir. Örneğin, 'List' ''' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''' '' tanımını ele alalım. (Örtük bf: CanBuild '. Repr, F-Bound tipi parametresidir ve Listenin İçinde Listedir [A], ancak TraversableLike'daki kod, 'List 'bilgisi olmadan yazılabilir. – wingedsubmariner

+0

Evet, sanırım sonunda tasarımımın bazılarını yeniden düşünmem gerekiyor. Bana öyle geliyor ki f-sınırlı polimorfizm sadece f-sınırlı bir süper tipten miras alındığında tip tanım düzeyinde kullanılmalıdır. Ancak, kodumda, yöntem düzeyinde kullanıldığı birkaç örnek var ... Bunun değişmesi gerektiğini hissediyorum. –

-1

Muhtemelen aşağıdaki uygulama ile bir şeyleri özlüyorum.

trait EventSourced[E] { 
    self => 

    type FBound <: EventSourced[E] { type FBound <: self.FBound } 

    def apply(event: E): FBound 
} 

trait Something[ES, E] 

def mapToSomething[E](
    eventSourced: ES forSome { 
    type ES <: EventSourced[E] 
    }): Something[eventSourced.type, E] = ??? 

class Test extends EventSourced[Boolean] { 
    type FBound = Test 
    def apply(event:Boolean):FBound = ??? 
} 

val x:Test = ??? 

mapToSomething(x)