2015-11-07 6 views
0

Я хотел бы сгенерировать тип со статическими функциями, который затем я могу использовать в функциях, которые становятся котировками, используя атрибут ReflectedDefinition. Мне представляется удобным способом перевести что-то в типы FSharp, используя FSharp для составления домена функций и типов, и выплескивать скомпилированный код обратно в его родную форму, получив преимущество проверки типов, VS intellisense, функций более высокого порядка и т.д. Для того, чтобы попробовать и начать работу у меня есть этот провайдер типа, в основном от копирования> вставило из различных статейМожет ли используемый тип использоваться в цитате - возникают ли вызовы TypeProvider в функциях ReflectedDefinition?

[<TypeProvider>] 
type CSoundTypeProvider(config: TypeProviderConfig) as this = 

    inherit ProvidedTypes.TypeProviderForNamespaces() 

    let namespaceName = "TestNamespace" 
    let thisAssembly = Assembly.GetExecutingAssembly() 

// config. 

    let intType = typeof<int> 
    let providedParam = ProvidedTypes.ProvidedParameter("prm", intType) 
    let providedFunction = ProvidedTypes.ProvidedMethod("TestMethod", [providedParam], intType, IsStaticMethod=true 
            , InvokeCode = fun args -> 
                // The 'args' parameter represents expressions that give us access to the 
                // instance on which the method is invoked and other parameters (if there are more) 
                let instance = args.[0] 
                // Now we can return quotation representing a call to MethodInfo 'p' with 'instance' 
                instance) 
    let csoundProvidedWrapper = ProvidedTypes.ProvidedTypeDefinition(thisAssembly, namespaceName, "TestType", None) 
    do csoundProvidedWrapper.AddMember(providedFunction) 
    do this.AddNamespace(namespaceName, [csoundProvidedWrapper]) 

и тестирование его с этим отражено определением:

[<ReflectedDefinition>] 
let myfn i j = 
    let k = i * j 
    let x = k + 2 
    let f = TestNamespace.TestType.TestMethod k 
    let ret = f + 2 
    ret 

Я разбор отраженное определение следующим образом:

<@ myfn @> |> println 

Println является функцией (копируется из другой статьи), который имеет многие из активных шаблонов для синтаксического анализа котировок, как Patterns.Call (None, DerivedPatterns.MethodWithReflectedDefinition (п), expList), который получает меня дерево выгрузки всего кода, за исключением для предоставленного статического метода. Является ли то, что я пытаюсь сделать, даже возможно? Если это так, что активный шаблон я вероятно пропустил из моей Println функции здесь:

let println expr = 
    let rec print expr = match expr with 
     | Patterns.Application(expr1, expr2) -> 
      // Function application. 
      print expr1 
      printf " " 
      print expr2 
     | Patterns.Call(None, DerivedPatterns.MethodWithReflectedDefinition(n), expList) -> 
      print n 
     | Patterns.Call(exprOpt, methodInfo, exprList) -> 
      // Method or module function call. 
      match exprOpt with 
      | Some expr -> print expr 
      | None -> printf "%s" methodInfo.DeclaringType.Name 
      printf ".%s(" methodInfo.Name 
      if (exprList.IsEmpty) then printf ")" else 
      print exprList.Head 
      for expr in exprList.Tail do 
       printf "," 
       print expr 
      printf ")" 
     | DerivedPatterns.Int32(n) -> 
      printf "%d" n 
     | Patterns.Lambda(param, body) -> 
      // Lambda expression. 
      printf "fun (%s:%s) -> " param.Name (param.Type.ToString()) 
      print body 
     | Patterns.Let(var, expr1, expr2) -> 
      // Let binding. 
      if (var.IsMutable) then 
       printf "let mutable %s = " var.Name 
      else 
       printf "let %s = " var.Name 
      print expr1 
      printf " in " 
      print expr2 
     | Patterns.PropertyGet(_, propOrValInfo, _) -> 
      printf "%s" propOrValInfo.Name 
     | DerivedPatterns.String(str) -> 
      printf "%s" str 
     | Patterns.Value(value, typ) -> 
      printf "%s" (value.ToString()) 
     | Patterns.Var(var) -> 
      printf "%s" var.Name 
     | _ -> printf "%s" (expr.ToString()) 
    print expr 

Если я не могу это сделать, какой подход вы рекомендовали бы для создания определений FSharp, что я могу использовать в кавычках? На меня в значительной степени повлиял проект FunScript, но он надеялся избежать шага, на котором, по-видимому, каждое определение дескриптора должно быть скомпилировано в отдельную DLL.

ответ

2

Большинство демонстрационных версий провайдера типа используют удаленных провайдеров, которые не производят реальные типы .NET. Когда вы используете поставщика стираемого типа, сгенерированные методы: удалены и заменены кодом, указанным в методе InvokeCode.

Допустим, у вас есть метод Foo, который стирает в someFunc с "Foo" в качестве аргумента:

myObj.Foo() ~> someFunc(myObj, "Foo") 

В цитатах, вы будете также видеть стертую версию (как в прямом <@ .. @> и в ReflectedDefinition):

<@ myObj.Foo() @> ~> <@ someFunc(myObj, "Foo") @> 

Способ, которым работает поставщик типа FunScript, заключается в том, что он генерирует некоторый фиктивный код, который содержит имя функции, так что он может затем сгенерировать соответствие JavaScript. Скажем, у вас есть:

<@ win.Alert(arg) @> ~> <@ invokeFunction("alert", win, arg) @> 

Чтобы сделать такой же вещи, вам нужно определить функцию как invokeFunction и генерировать соответствующий InvokeCode. Затем вы можете искать вызовы в invokeFunction в сгенерированной цитате и выполнять любую специальную вещь, которую вам нужно делать. Немного сложно понять, что именно вы пытаетесь сделать, но это должно по крайней мере указывать на вас в правильном направлении.

+0

Большое спасибо за то, что нашли время, чтобы объяснить это. Я не оценил, что определение ** InvokeCode ** так важно. Я только пытаюсь сгенерировать типы настолько же глубокие, как открытый интерфейс провайдера типов, отсюда и немой код в моем примере. В свете этой информации, возможно, создание провайдера типов является излишним для того, что я действительно пытаюсь сделать, что представляет собой интерфейс. –