2011-08-06 17 views
11

Bir kod teklifini derlemeye derlemenin bir yolu olup olmadığını bilmek ister misiniz?F # Kod teklifini bir derlemeye nasıl derlerim

Ben örneğin Exp<_> nesne üzerinde CompileUntyped() veya Compile() çağırmak mümkün olduğunu anlıyoruz:

Ancak
let x = <@ 1 * 2 @> 
let com = x.Compile() 

, nasıl komple olarak diske com devam edebilir?

Teşekkürler.

+2

PowerPack'in bunu destekleyip desteklemediğinden emin değilim. Ama bir yana, PowerPack'i hiç kullanmamayı tavsiye etmem. Kodları genellikle buggy veya çok yavaştır. System.Reflection.Emit kullanarak kendi derleyicinizi veya değerlendiricinizi sıfırdan yazmak, muhtemelen daha iyi sonuçlar verecektir. Ayrıca F # 'nin teklifleri optimize etmemesi gibi bir problem de vardır, örneğin eşleme, normal F # derlemesinde CIL'de olduğu gibi atlama komutu yerine bir/sonra/else dizisi olur. – t0yv0

+0

Merhaba, bunun için teşekkürler, sanırım onlara alternatifler bakacağım (Reflection.Emit sözünü ettiğin gibi). – Ncc

+0

Bu yararlı bulabilirsiniz: http://stackoverflow.com/questions/2682475/converting-f-quotations-into-linq-expressions ve http://stackoverflow.com/questions/1618682/linking-a-net-expression Yeni bir proje başlatmak için -t-new-assembly- – JPW

cevap

12

Sen desen eşleştirme ile bir F # Kod Alıntılar değerlendirebilirsiniz:

open Microsoft.FSharp.Quotations.Patterns 

let rec eval = function 
    | Value(v,t) -> v 
    | Call(None,mi,args) -> mi.Invoke(null, evalAll args) 
    | arg -> raise <| System.NotSupportedException(arg.ToString()) 
and evalAll args = [|for arg in args -> eval arg|] 

let x = eval <@ 1 * 3 @> 

F# PowerPack, Unquote, Foq ÖSS projeleri veya daha eksiksiz uygulamaları için bu snippet bakınız.

Reflection.Emit kullanarak bir F # Kod Teklifi yapabilirsiniz define a dynamic method derlemek için:

open System 
open System.Reflection 

let createAssembly quotation = 
    let name = "GeneratedAssembly" 
    let domain = AppDomain.CurrentDomain 
    let assembly = domain.DefineDynamicAssembly(AssemblyName(name), AssemblyBuilderAccess.RunAndSave) 
    let dm = assembly.DefineDynamicModule(name+".dll") 
    let t = dm.DefineType("Type", TypeAttributes.Public ||| TypeAttributes.Class) 
    let mb = t.DefineMethod("f", MethodAttributes.Public, typeof<int>, [||]) 
    let il = mb.GetILGenerator() 
    quotation |> generate il 
    il.Emit(OpCodes.Ret) 
    assembly.Save("GeneratedAssembly.dll") 

createAssembly <@ 1 + 1 @> 

bakınız:

open System.Reflection.Emit 

let rec generate (il:ILGenerator) = function 
    | Value(v,t) when t = typeof<int> -> 
     il.Emit(OpCodes.Ldc_I4, v :?> int) 
    | Call(None,mi,args) -> 
     generateAll il args 
     il.EmitCall(OpCodes.Call, mi, null) 
    | arg -> raise <| System.NotSupportedException(arg.ToString()) 
and generateAll il args = for arg in args do generate il arg 

type Marker = interface end 

let compile quotation = 
    let f = DynamicMethod("f", typeof<int>, [||], typeof<Marker>.Module) 
    let il = f.GetILGenerator() 
    quotation |> generate il 
    il.Emit(OpCodes.Ret) 
    fun() -> f.Invoke(null,[||]) :?> int 

let f = compile <@ 1 + 3 @> 
let x = f() 

bir derlemeye derlemek için tekrar bir yöntemle bir tür oluşturmak için Reflection.Emit kullanmak Daha eksiksiz bir uygulama için Fil projesi (F # ila IL).

+0

+1 bunu yapar! – Govert

+0

https://github.com/eiriktsarpalis/QuotationCompiler uygulamasının uygulanması, Kod Tırnaklarını derlemek için Yansıma'yı kullanma gereğini ortadan kaldırmıştır. Bu uygulama, Microsoft.FSharp.Compiler ad alanını, daha önce erişilemeyen büyük olasılıkla kullanmaktadır ... – Sam

+0

@Sam iyi nokta Eirik'in Quotation Derleyicisi, muhtemelen şimdi gitmenin yoludur –

İlgili konular