родовая утка, набравшая F#?
Используя ограничения Let inline и member, я смогу сделать duck typing для известных членов, но что, если я хотел бы определить универсальную функцию следующим образом:
Пусть duckwrapper duck = ...
С подписью 'b - >' a и где возвращаемое значение будет объектом, который реализует 'a (который будет интерфейсом) и перенаправляет вызовы duck.
Я сделал это в C#, используя отражение.Но мне интересно, если F # отражение, цитаты или другие конструкции так будет проще.
Какие-нибудь предложения о том, как это сделать?
EDIT прочитав ответ Тимса, я подумал, что дам немного больше деталей
То, о чем я думал, когда писал об использовании цитат для помощи, было что-то вроде:
{new IInterface with member x.SayHello() = !!<@ %expr @>}
!! оператор, переводящий цитату в функцию, и %expr, являющийся единицей работы для метода. Я мог бы перевести выражение в функцию (я думаю), но не знал бы, как
Из конечно, это не будет делать трюк полностью, так как IInterface будет 'a, где я надеюсь, что отражение F# может иметь некоторые удобные функции, чтобы я мог построить тип, основанный на объекте типа и некоторых значениях функции
EDIT В качестве обновления к ответу Томаса Петричека я дам некоторый код, чтобы объяснить мои потребности
type SourceRole =
abstract transfer : decimal -> context
and context(sourceAccount:account, destinationAccount) =
let source = sourceAccount
let destination = destinationAccount
member self.transfer amount =
let sourcePlayer =
{new SourceRole with
member this.transfer amount =
use scope = new TransactionScope()
let source = source.decreaseBalance amount
let destination = destination.increaseBalance amount
scope.Complete()
context(source,destination)
}
sourcePlayer.transfer(amount)
, что является попыткой перенести "хрестоматийный" пример DCI В F#. Источником и назначением являются роли DCI. Это идея, что любой объект данных, который придерживается определенного контракта, может играть в них. В этом случае договор прост. нужен источник memberfunction называется decreaseBalance и назначения нужна функция-член называется increaseBalance. Я могу сделать это для этого конкретного случая с ограничениями Let inline и member. Но я хотел бы написать набор функций, которые дают интерфейс и объект. В этом случае это может быть источник (как объект) и
type sourceContract =
abstract decreaseBalance : decimal -> sourceContract
Как тип. Результатом будет объект типа sourceContract, который будет передавать вызовы метода методу с тем же именем на исходном объекте.
2 ответа:
Вы можете скомпилировать цитаты F#, используя компоненты изF# PowerPack . Поэтому я думаю, что вы можете использовать цитаты для создания и выполнения кода во время выполнения. Если вы напишете цитату, представляющую функцию , и скомпилируете ее, вы получите значение функции, которое можно использовать для реализации интерфейса. Вот тривиальный пример:
#r "FSharp.PowerPack.Linq.dll" open Microsoft.FSharp.Quotations open Microsoft.FSharp.Linq.QuotationEvaluation // Create a part using "Expr." calls explicitly let expr = Expr.Value(13) // Create a part using quotation syntax let expr2 = <@ (fun x -> x * %%expr) @> // Compile & Run let f = expr2.Compile()() f 10
Вы можете смешивать синтаксис цитат и вызовы
Я не совсем уверен, что понимаю, что именно вы пытаетесь сделать, поэтому, если вы можете предоставить более подробные сведения, я могу дать более конкретный ответ.Expr
, что облегчает составление кода из базовых блоков. Компиляция немного глупа (в настоящее время), так что сгенерированный код не будет таким же эффективным, как обычный код F# (но вам нужно будет измерить его в вашем случае).
F# reflection (
Microsoft.FSharp.Reflection
)-это F# - дружественная оболочка вокруг простыхSystem.Reflection
API, поэтому я не думаю, что она что-то добавит здесь.Цитаты не могут определить новые типы: (вам нужно будет определить новый тип, чтобы сделать ваш интерфейс на основе утки ввода)
> <@ { new IInterface with member x.SayHello = "hello" } @>;; <@ { new IInterface with member x.SayHello = "hello" } @>;; ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ stdin(7,4): error FS0449: Quotations cannot contain object expressions > <@ type Test() = class end @>;; <@ type Test() = class end @>;; ---^^^^ stdin(8,4): error FS0010: Unexpected keyword 'type' in quotation literal
Размышление.Эмиссия-это все еще способ пойти с этим.
Редактировать:
Я надеюсь, что F# reflection может иметь некоторые удобные функции, чтобы я мог построить тип, основанный на объекте типа и некоторой функции значения
Боюсь, что нет. вот документация по F# reflection: http://msdn.microsoft.com/en-gb/library/ee353491.aspx