Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute F# code found in a string in a compiled F# program?

Tags:

f#

How do I execute F# code from a string in a compiled F# program?

like image 899
Moonlight Avatar asked Jul 21 '09 00:07

Moonlight


2 Answers

Here's a little script that uses the FSharp CodeDom to compile a string into an assembly and dynamically load it into the script session.

It uses a type extension simply to allow useful defaults on the arguments (hopefully let bound functions will support optional, named and params arguments in the near future.)

#r "FSharp.Compiler.dll"
#r "FSharp.Compiler.CodeDom.dll"

open System
open System.IO
open System.CodeDom.Compiler
open Microsoft.FSharp.Compiler.CodeDom

let CompileFSharpString(str, assemblies, output) =
        use pro = new FSharpCodeProvider()
        let opt = CompilerParameters(assemblies, output)
        let res = pro.CompileAssemblyFromSource( opt, [|str|] )
        if res.Errors.Count = 0 then 
             Some(FileInfo(res.PathToAssembly)) 
        else None

let (++) v1 v2   = Path.Combine(v1, v2)    
let defaultAsms  = [|"System.dll"; "FSharp.Core.dll"; "FSharp.Powerpack.dll"|] 
let randomFile() = __SOURCE_DIRECTORY__ ++ Path.GetRandomFileName() + ".dll"   

type System.CodeDom.Compiler.CodeCompiler with 
    static member CompileFSharpString (str, ?assemblies, ?output) =
        let assemblies  = defaultArg assemblies defaultAsms
        let output      = defaultArg output (randomFile())
        CompileFSharpString(str, assemblies, output)     

// Our set of library functions.
let library = "

module Temp.Main
let f(x,y) = sin x + cos y
"
// Create the assembly
let fileinfo = CodeCompiler.CompileFSharpString(library)

// Import metadata into the FSharp typechecker
#r "0lb3lphm.del.dll"

let a = Temp.Main.f(0.5 * Math.PI, 0.0)     // val a : float = 2.0

// Purely reflective invocation of the function.
let asm = Reflection.Assembly.LoadFrom(fileinfo.Value.FullName)
let mth  = asm.GetType("Temp.Main").GetMethod("f")

// Wrap weakly typed function with strong typing.
let f(x,y) = mth.Invoke(null, [|box (x:float); box (y:float)|]) :?> float

let b = f (0.5 * Math.PI, 0.0)              // val b : float = 2.0

To use this in a compiled program you would need the purely reflective invocation.

Of course this is a toy compared to a full scripting API that many of us in the community have urgently requested.

best of luck,

Danny

like image 102
Daniel Asher Avatar answered Nov 10 '22 06:11

Daniel Asher


Are you looking for an Eval function?

You might want to try looking at this blog post:

http://fsharpnews.blogspot.com/2007/02/symbolic-manipulation.html

If you read in your expressions into these kind of symbolic datastructures, they are pretty easy to evaluate.


Or, perhaps you are looking for scripting support:

http://blogs.msdn.com/chrsmith/archive/2008/09/12/scripting-in-f.aspx


If you really want dynamic compilation, you could do it with the F# CodeDom provider.

like image 5
Robert Harvey Avatar answered Nov 10 '22 05:11

Robert Harvey