родовая утка, набравшая 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 3

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