общая утка печатать на F #? - PullRequest
       27

общая утка печатать на F #?

3 голосов
/ 14 декабря 2010

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

let duckwrapper <'a> duck = ...

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

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

type sourceContract = 
   abstract decreaseBalance : decimal -> sourceContract

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

Ответы [ 2 ]

4 голосов
/ 14 декабря 2010

Отражение F # (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

Reflection.Emit все еще способ пойти с этим.

Edit:

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

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

2 голосов
/ 15 декабря 2010

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

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

...