Типичная утка, набирая в F #?

используя let inline и ограничения для членов, я смогу сделать утиную печать для известных членов, но что, если я хотел бы определить такую ​​общую функцию:

let duckwrapper < 'a > duck =...

с сигнатурой 'b → ' a и где возвращаемое значение будет объектом, который реализовал 'a (который был бы интерфейсом) и перенаправил вызовы на утку.

Я сделал это на С#, используя Reflection.Emit, но мне интересно, облегчит ли F # отражение, цитаты или другие конструкции.

Любые предложения о том, как это сделать?

ИЗМЕНИТЬ после прочтения ответа Тима я подумал, что дам немного больше информации

То, о чем я думал, когда писал об использовании цитат для помощи, было примерно таким:

{new IInterface with member x.SayHello() = !!<@ %expr @>}

!! являющийся оператором, переводящим цитату в функцию, а% expr - единицей работы для метода. Я бы смог перевести выражение в функцию (я думаю), но не знал, как

Конечно, это не сделало бы трюк полностью, так как IInterface был бы "a, где я надеюсь, что отражение F # может иметь некоторые удобные функции, чтобы я мог построить тип на основе объекта типа и некоторых значений функций

ИЗМЕНИТЬ Как обновить Tomas Petricek ответ, я дам некоторый код, чтобы объяснить мои потребности.

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. Это идея, что любой объект данных, который придерживается конкретного контракта, может их воспроизвести. В этом случае договор прост. источник нуждается в функции-члене, которая называется reduceBalance, а для назначения требуется функция-член, называемая boostBalance. Я могу выполнить это для этого конкретного случая с let inline и ограничениями членов. Но я бы хотел написать набор функций, которые дали интерфейс и объект. В этом случае это может быть источник (как объект) и

type sourceContract = 
   abstract decreaseBalance : decimal -> sourceContract

как тип. Результатом будет объект типа sourceContract, который вызовет метод метода методу с тем же именем в исходном объекте.

+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 # -код (но вам нужно будет его измерить в вашем случае).

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

+2
источник

F # reflection (Microsoft.FSharp.Reflection) - это дружественная оболочка F # вокруг простых API System.Reflection, поэтому я не думаю, что она что-то добавит здесь.

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

> <@ { 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

Reflection.Emit по-прежнему подходит для этого.

Edit:

Я надеюсь, что отражение F # может иметь некоторые удобные функции, чтобы я мог построить тип на основе объекта типа и некоторых значений функций

Я боюсь, что нет. Здесь документация по отражению F #: http://msdn.microsoft.com/en-gb/library/ee353491.aspx

+4
источник

Посмотрите другие вопросы по меткам или Задайте вопрос