F #: Функции перегрузки - PullRequest
6 голосов
/ 14 февраля 2010

Мой вопрос в некоторой степени связан с этим - Функции с общими типами параметров - но я не могу понять, как делать то, что я хочу.

Я хочу определить функцию 'Потомки', чтобы обернуть вызов 'Потомки' в различных классах C # следующим образом:

пусть имя потомков (xDocument: XDocument) = xDocument. Имя потомков

пусть имя потомков (xElement: XElement) = xElement. Имя потомков

Этот подход не работает, потому что у нас есть дублирующее определение «потомков».

Я думал, что было бы возможно использовать встроенную функцию и статически разрешить параметры, чтобы определить следующий метод, чтобы сделать это вместо этого:

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

Но я получаю эту ошибку при попытке сделать это:

Поиск по объекту неопределенного типа на основе информации до этой программной точки. Аннотации типа могут потребоваться до этой точки программы, чтобы ограничить тип объекта. Это может разрешить поиск, который будет разрешен.

Есть ли способ, которым я могу написать эту вторую функцию, чтобы делать то, что я хочу?

Ответы [ 2 ]

14 голосов
/ 14 февраля 2010

Вообще говоря, я думаю, что типы шляп, такие как ^x, возможно, используются слишком часто (по крайней мере, судя по количеству вопросов о них в SO). Это мощная функция, но она действительно была разработана главным образом для решения проблем с общей арифметикой. Я думаю, что они могут сделать программы на F # излишне сложными.

Если вы работаете только с XDocument и XElement, то ответ довольно прост, потому что вы можете использовать XContainer, который является их общим базовым классом и имеет метод Descendants:

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

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

Если вы не можете найти общий базовый класс, тогда вы, конечно, можете использовать тип ^a, но вы также можете использовать обычную перегрузку, которая возможна в F #, но работает только для членов типа объекта:

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

(Поскольку вы сослались на вопрос с ответом, который уже показывает, что перегрузка работает с участниками, это, вероятно, не является чем-то новым для вас. Но это может быть полезно для тех, кто найдет этот вопрос в будущем). 1015 *

4 голосов
/ 14 февраля 2010

Код ниже компилируется (и наводит на мысль о синтаксисе, необходимом для вызова статических функций ограничения членов).

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...