2010-02-14 26 views
6

Soruma ilişkin bir sorun var - Functions with generic parameter types - ama ne istersem onu ​​halledemiyorum.F #: Aşırı yükleme işlevleri

Ben tanımlamak istediğiniz yüzden gibi çeşitli C# sınıfları üzerinde Torunları ' 'kökenini çağrısı sarmak için işlev':

soyundan adı (XDocument: XDocument) let = xDocument.Descendants

kökenini izin

isim name (xElement: XElement) = xElement.Descendants name

Bu yaklaşım işe yaramıyor, çünkü 'torunlar' yinelenen bir tanımımız var.

ben yerine bunu yapmak için satır içi işlevi faydalanmak ve statik olarak aşağıdaki yöntemi tanımlamak için parametreleri çözmek mümkün olacağını düşündüm:

let inline descendants name (xml : ^x when ^x : (member Descendants : XName -> seq<XElement>)) = 
    xml.Descendants name 

Ama bunu yapmaya çalışıyor bu hatayı alıyorum : Bu program noktasından önceki bilgilere dayanarak belirsiz türdeki nesneye bakın. Nesnenin türünü kısıtlamak için bu program noktasından önce bir tip açıklama gerekebilir. Bu, aramanın çözülmesine izin verebilir.

İstediğimi yapmak için ikinci işlevi yazmamın bir yolu var mı?

cevap

4

Aşağıdaki kod derleyicileri derler (ve statik üye kısıtlama işlevlerini çağırmak için gereken sözdizimini önerir).

open System.Xml.Linq 

let descendants1 name (xDocument:XDocument) = xDocument.Descendants name 

let descendants2 name (xElement:XElement) = xElement.Descendants name 

let inline descendants name (xml : ^x when ^x : (member Descendants : XName -> seq<XElement>)) = 
    (^x : (member Descendants : XName -> seq<XElement>) (xml,name)) 

let xd = XDocument.Load("http://www.somexml.com") 
let ds = descendants (XName.op_Implicit "foo") xd 
let xe = XElement.Load("http://www.somexml.com") 
let eds = descendants (XName.op_Implicit "foo") xe 
14

Genel olarak konuşursak, böyle ^x olarak şapka-tipleri belki (SO onlar hakkında sorular sayısına bakılırsa, en azından) çok fazla kullanıldığından emin düşünüyorum. Bu güçlü bir özellik, ama esas olarak genel aritmetik problemleri çözmek için tasarlanmıştı. F # programlarını gereksiz bir şekilde karmaşık hale getirebilirler.

Eğer XDocument ve XElement ile sadece çalışıyorsanız, o zaman cevap size XContainer kullanabilirsiniz çünkü ortak taban sınıfı olan oldukça basittir ve Descendants yöntemi vardır:

let descendants name (xml:XContainer) = xml.Descendants(name) 

// Both of these will work fine 
descendants (XName.Get "foo") xd 
descendants (XName.Get "foo") xe 

sen bulamıyorsanız ortak bir taban sınıfı, o zaman tabii ki ^a türü kullanabilirsiniz, ama aynı zamanda F # mümkündür, ancak nesne tipi üyeleri için çalışır, normal aşırı yüklenmesini, kullanabilirsiniz:

type Xml = 
    static member Descendants(name, x:XDocument) = x.Descendants(name) 
    static member Descendants(name, x:SomeOtherClass) = x.SomeOtherDescendants(name) 

// The usage looks like this: 
Xml.Descendants(XName.Get "foo", xd) 
Xml.Descendants(XName.Get "foo", new SomeOtherClass()) 

(Zaten aşırı yüklemenin üyelerle çalıştığını gösteren bir cevabı olan bir soruya başvurduğun için, bu muhtemelen senin için yeni bir şey değil. Ancak bu soruyu gelecekte bulabilecek başkalarına da faydalı olabilir).

+0

Ah Aslında aşırı yüklemenin aslında üyeler için çalıştığını fark etmedim, açıkça diğer gönderiyi yeterince okumamıştı! Ayrıca, her ikisi de XContainer'dan miras aldıklarını anlayamadılar, bu çok daha iyi bir çözümdür. –

+0

Aslında normal aşırı yüklemeyi denedim ve derleyici, "Descendants" olarak adlandırılan 2 üyenin aynı sayıda argümanla birlikte olduğunu söyler –

+0

Bazılarında sürümleri, F # derleyicisi gereklidir '[]' aşırı yükleme yaparken kullanılacak, ancak hangi sürümde kaldırıldığından emin değilim ... F # RC'de daha basit bir örnek çalıştım (iki yöntem , her iki argüman ile) ve iyi çalıştı (OverloadID' olmadan). –