‘Embedding’ F# in PowerShell

by Doug Finke on July 27, 2007

in F#,PowerShell

Jeffery Snover, architect of PowerShell, presented a PowerShell script with embedded C# code to invoke a Win32API.

Here is a first attempt at embedding F# in PowerShell. The key difference is the the F# code is written to disk, compiled and the resulting DLL is then loaded into memory. The embedded C# approach uses the System.CodeDom to compile and generate the executable in memory.

program

The F# code, lines 6 through 13, are in a PowerShell here-string (5 and 14). The program is saved to disk (16), the F# compiler invoked (18), the compiled DLL is loaded (22) finally the get method is invoked (24).

results

Notes

The F# get method is generated as static. Calling static members requires the fully qualified namespace, class name, two colons and the member name. [Strangelights.Fibonacci]::get()

If you want to find the static methods/properties of a class, use the Get-Member cmdlet with the switch -Static on the already loaded DLL.

Get-Member

F# compiles to a .Net assembly, so any .Net language can interoperate with it. Conversely, F# can use assemblies generated by other .Net languages.

{ 2 comments… read them below or add one }

Mr. Spock 12.28.09 at 11:25 am

Very interesting !!
I made some modifications to your code to allow it compile F# into memory.

Hope it helps:

#path to FSharp Compiler Provider assembly DLL
$fsharp_codedom = "$env:ProgramFiles (x86)\FSharp-1.9.7.8\bin\FSharp.Compiler.CodeDom.dll";

#load compiler assembly
$codedom_assy=[System.Reflection.Assembly]::LoadFrom($fsharp_codedom);

#instantiate compiler and parameters
$compiler = new-object -type Microsoft.FSharp.Compiler.CodeDom.FSharpCodeProvider;
$compilerParameters = new-object -type System.CodeDom.Compiler.CompilerParameters;

#force assembly to be compiled in memory
$compilerParameters.GenerateInMemory=$true;

# FSharp Source
$source=@"
#light
module Strangelights.Fibonacci
let fibs =
(1,1) |> Seq.unfold
(fun (n0,n1) ->
Some(n0, (n1, n0 + n1)))

let get n =
Seq.nth n fibs

"@

$result = $compiler.CompileAssemblyFromSource($compilerparameters,$source);
if ($result.Errors.HasErrors){ $source;$result.Errors;break}

#calling FSharp functions from powershell
1..40| ForEach { "{0} {1}" -f $_, [Strangelights.Fibonacci]::get($_) }

Tahir Hassan 06.12.14 at 3:55 am

I installed the “Old F# PowerPack” and added the following function:


Add-Type -Path 'C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll'
Add-Type -Path 'C:\Program Files (x86)\FSharpPowerPack-4.0.0.0\bin\FSharp.Compiler.CodeDom.dll'

Function Add-FSharpType([string]$Path=$null, [string]$TypeDefinition=$null) {
if ( (-not $Path) -and (-not $TypeDefinition) ) {
Write-Host '***** Path or TypeDefinition must be given ****' -ForegroundColor 'Red'
} else {
$FSharpCodeProvider = New-Object Microsoft.FSharp.Compiler.CodeDom.FSharpCodeProvider
$FSharpCode = if ($Path) { [System.IO.File]::ReadAllText($Path) } else { $TypeDefinition }
Add-Type -TypeDefinition $FSharpCode -CodeDomProvider $FSharpCodeProvider
}
}

You can supply either a -Path argument or a -TypeDefinition (a string containing the F# code) argument. Here is how I would use it with the above Fibonacci code:


$fibCode = @"
module Strangelights.Fibonacci
let fibs =
(1,1) |> Seq.unfold
(fun (n0,n1) ->
Some(n0, (n1, n0 + n1)))
let get n =
Seq.nth n fibs
"@

Add-FSharpType -TypeDefinition $fibCode

I wrote this up on my blog:

Embedding F# in PowerShell.

Leave a Comment

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>