Friday 29 April 2011

IronScheme from Powershell

I thought i would mix two things I like. PowerShell and IronScheme.
Scheme it is a lot easier to write very powerful things incredibly easily.
While it is also possible to do this in PowerShell, it naturally lacks the grace that Scheme has.
Ostensibly my intention is to be able to write core functionality in IronScheme, and then make use of it from PowerShell.
To that end, here is the application of a couple of IronSchemes extension methods to the string type.

Be aware that this requires PowerShell v2 and IronScheme - the latter is available here : http://ironscheme.codeplex.com/

Here's the content of SchemeTypeExtensions.ps1xml which i placed in my $pshome directory



<?xml version="1.0" encoding="utf-8"?>
<Types>
  <Type>
    <Name>System.String</Name>
    <Members>
      <ScriptMethod>
        <Name>Eval</Name>
        <Script>
          switch ($args.Count) {
            0 { [IronScheme.RuntimeExtensions]::Eval($this) }
            default { [IronScheme.RuntimeExtensions]::Eval($this,$args) }
          }
        </Script>
      </ScriptMethod>
    </Members>
  </Type>
  <Type>
    <Name>System.Delegate</Name>
    <Members>
      <ScriptMethod>
        <Name>ToSchemeProcedure</Name>
        <Script>
          switch ($args.Count) {
            0 { [IronScheme.RuntimeExtensions]::ToSchemeProcedure($this) }
            default { throw "No overload for ToSchemeProcedure takes the specified number of parameters." }
          }
        </Script>
      </ScriptMethod>
    </Members>
  </Type>
</Types>





To apply this I place the following in my profile.ps1


[Void][Reflection.Assembly]::LoadFrom('C:\Program Files\IronScheme\IronScheme.dll')
Update-TypeData -PrependPath "$pshome\SchemeTypeExtensions.ps1xml"

It's then pretty straightforward to evaluate Scheme
"(+ 2 2)".Eval()

To accept parameters, the easiest manner I have found it to have a lambda expression and then call the call method.

 "(lambda (x)(* x x) )".Eval().Call(4)

An example of that packaged into a function would be something along the lines of


Function Square-Item { 
[CmdletBinding(SupportsShouldProcess=$true)]
Param(
[parameter(Mandatory=$true,
ValueFromPipeline=$true,
Position=0)]
$Number) 
BEGIN { 
$x = "(lambda (x)(* x x) )".Eval() 

PROCESS { 
$x.Call($Number) 
}
}


It would be nice to make more use of the pipeline feature of PowerShell, but I'm going to leave that for another day.