2017-01-19 20 views
6

Tek tip bir parametre ile F # içinde genel bir sınıf var ve fabrika yöntemleri içeren statik bir sınıf oluşturmak istiyorum. Sınıflarımı yazdığımda, F # derleyici "kapsamından kaçan bir tür değişkeni" ile ilgili bir hata üretir. Sorum şu: hata neden ve nasıl düzeltileceği. Ben tip Foo<'a> fabrika yöntemleri çağırmak edebilmek istiyorum çünküTür değişkeni, jenerik ve jenerik olmayan sınıf birleştirirken kapsam dışına çıkmaktadır

type Foo<'a>(element : 'a) = 

    member this.Copy() = Bar.Create(element) 

and Bar = 

    static member Create(element : 'a) = new Foo<'a>(element) 

tiplerinde karşılıklı Yinelemesiz yoktur: Sorunu gösteren asgari boy pasajını oluşturduk

statik sınıf. Yukarıdaki kod parçacığı derlenmiyor ve hata şu şekildedir: "Tür çıkarımı, tür değişkeninin a, kapsamından çıkmasına neden oldu. Açık bir tip parametre bildirimi eklemeyi veya kodunuzu daha az genel olacak şekilde ayarlamayı düşünün." Hata, Bar sınıfının Create yönteminde bulunan olarak kaydedilir. Maalesef, sorunu gerçekten anlamıyorum ve nasıl düzelteceğimi bilmiyorum. Herhangi bir fikir?

İşte ek bir gözlem. Snippet

derlemez. Bu nedenle, sorun, Foo<'a> sınıfının Copy() yöntemine dayanarak yapılan tür çıkarsama ile ilgili görünmektedir. Bundan başka, söz konusu pasaj

type Foo<'a>(element : 'a) = 

    member this.Copy() = Bar.Create(element) 

and Bar = 

    static member Create<'a>(element) = new Foo<'a>(element) 

da hata ile, derleme değil (statik yöntem açıkça genel yapılır) kodu, bir daha fazla C# -benzeri versiyonu yeterli değil genel "Bu kod olmasıdır. tip değişkeni 'a, kapsamı dışında kalacağı için genelleştirilemezdi.'

cevap

6

Özyinelemeli üyeler için çıkarımda bulun, genellikle tanımların en azından bazılarında tür açıklamaları gerektirir. En azından sizin basitleştirilmiş repro içinde olabildiğince Ancak, bazen, yeniden sipariş tanımları Bundan kaçınmak için:

type Bar = 
    static member Create(element) = Foo(element) 
and Foo<'a>(element:'a) = 
    member this.Copy() = Bar.Create(element) 

(Ben bile Bar.Create içinde element Ek açıklamayı kaldırmış dikkat edin).

Maalesef, belirli bir durumda ne tür ek açıklamaların gerekeceğini tam olarak anlamak için kolay anlaşılır bir açıklama olduğunu bilmiyorum.

2

Aslında tipi değişken 'a çözülmemiş olma konusunda, farklı bir hata görüyorum ve ben 'a ile paremetreleme Bar'da etrafında alabilirsiniz:

type Foo<'a>(element : 'a) = 
    member this.Copy() = Bar.Create(element) 

and Bar<'a> = 
    static member Create(element : 'a) = new Foo<'a>(element) 

Korkarım ben yok çok Bu nedenle, karşılıklı olarak özyinelemeli türlerinizin bulunduğu senaryoda bunun neden gerekli olduğu ve ayrı bir Bar türüne sahip olduğunuzda değil.

Karşılıklı özyinelemeli türlerden sakınma eğilimindeyim - onlar olmadan yapamayacağınız durumlar nadirdir. Çoğu zaman özyinelemeden kaçınmak için kodu yeniden yapılandırabilir ve genellikle gerekirse daha kolay okunan ve yeniden düzenlenecek bir şeyle sonuçlanır.

+2

Karşılıklı özyineleme türlerini körfezde tutmakla ilgili yorumda bulunuldu. –

4

Bu jenerik Bar yapmadan iş gibi görünüyor:

type Foo<'a>(element : 'a) = 
    member this.Copy() = Bar.Create element 
and Bar = 
    static member Create<'a>(element : 'a) : Foo<'a> = Foo(element) 

Online Demo

sadece deneme yanılma yoluyla bulunması neden Hiçbir fikrim yok.

+1

Bu garip bir şey. Belki de 'Oluştur' sonucunun bir "Foo <'a>" olduğu ve ek açıklama olmaksızın "Foo" türü ve "Oluştur" yöntemindeki tür değişkenleri arasında bir etkileşim vardır. Bu şekilde çalışması beklendiğine inanamıyorum. – scrwtp