F# — Background

F# is a functional programming language derived from OCAML, which in turn has a shared ancestry with the Standard ML.

F# uses a syntax derived from OCAML but has many additional features in particular making it interface better with .NET constructs (as it compiles to the same CLR virtual machine as other .NET languages). Thus it should be easy to call the NAG Library for .NET from F#, and so it is, however the resulting interface doesn't always lead to idiomatic functional programming calling conventions. In this post I hope to show some reasons for this, and also show how with a few lines of F#, one can produce alternative interfaces to the NAG library that may allow more natural functional use, and be tuned to the particular requirements of your application.

F# is a very expressive language that is designed to support many different programming styles, although with a strongly functional foundation. As such there are several styles in which one may define a function (method). One of the distinguishing features of the ML family of languages is that they are strongly typed but that (when restricted to the core functional features) types never need to be explicitly declared, the expressions are statically analyzed at compile time and the type inferred.

F# may be used in two ways; as a compiler (compiling to CIL code as is done for C# or VB.NET) but also as an interactive interpreter that offers a read eval print loop interface familiar to lisp programmers and users of systems such as MATLAB or Maple.

Before looking at some specific examples from the NAG library, I want to look at a simpler example of a function for adding two numbers.

Sum Example

The first example uses a style that looks perhaps most familiar. Note however that unlike many imperative programming languages, F# functions only ever take a single argument. (a,b) here does not represent a pair of values but a single value, being a pair of integers (represented by the type int * int.

// sum_tuple declaration
> let sum_tuple (a,b) = a + b;;
val sum_tuple : int * int -> int

A more idiomatically functional style is the curried form, where instead of taking a sequence of values as input, the function takes one integer, returning a function which is in turn applied to the second integer, returning the sum.

// sum_curried declaration
> let sum_curried a  b = a + b;;
val sum_curried : int -> int -> int

As well as variables holding values (int in this case) ML based languages allow variables that hold references (pointers) to values (the type int ref here). the assignment operator := updates the referenced value (while the reference binding itself doesn't change). Passing such a reference type is one way to simulate the “output parameters” of functions or subroutines in imperative languages. The unit type shown as the return type is similar to void function in C, or a subroutine in Fortran.

// sum_ref declaration
> let sum_ref (a,b,r) = r := a + b;;
val sum_ref : int * int * int ref -> unit

In addition to the reference types derived from ML, F# provides a syntax to the .NET mechanisms of passing value types by reference. The example below uses the type annotation r:byref<int> to force this mechanism to be used, and uses the assignment operator <- rather than := to update the value. Passing a value type by reference rather than passing a parameter of reference type isn't something one would often do in native F# code, however methods derived from .NET libraries written in other languages often derive these types in F#.

// sum_byref declaration
> let sum_byref (a,b,r:byref<int>) = r <- a + b;;
val sum_byref : int * int * byref<int> -> unit

These four definitions may used as follows to calculate 3 = 1 + 2:

// Simple sum examples

> let r1 = sum_tuple (1,2);;
val r1 : int = 3

> let r2 = sum_curried 1 2;;
val r2 : int = 3

> let rr3 = ref 0;;
val rr3 : int ref = {contents = 0;}
> sum_ref (1,2,rr3);;
val it : unit = ()
> let r3 = !rr3;;
val r3 : int = 3

> let mutable r4 = 0;;
val mutable r4 : int = 0
> sum_byref(1,2,&r4);;
val it : unit = ()
> r4;;
val it : int = 3

The first two forms are clearly a bit more convenient, however the second two forms, which require the declaration of a variable to hold the result, are not hard and should be familiar to anyone used to a more imperative programming style. This essentially is a function of the main design aims of F#, that it should stress the functional approach, but give full access to any .NET methods even if they are designed for an imperative or Object Oriented rather than functional, declarative interface. The extra verbosity of the use of references is over exaggerated in these examples as I am using the interactive F# system and using the ;; terminator to cause the system to echo the value and type of each expression. This is a useful aid to see what's happening, but in practice one would often use the compiler which does not echo types at each stage, or not use the ;; terminator on every line if using the interactive system.

The benefits of the tuple or curried version when used in a functional programming language like F# are more apparent when functions are composed. If one wanted to calculate (1+1) + (2+2) (ignoring the fact that (1+1) + (2+2) is already valid F# ) then as sum_tuple and sum_curried are side effect free functions returning results they may be composed in a very natural way:

// composing sum examples (functional)
> let c1=sum_tuple (sum_tuple(1,1),sum_tuple(2,2));;
val c1 : int = 6

> let c2=sum_curried (sum_curried 1 1) (sum_curried 2 2);;
val c2 : int = 6

The signatures of sum_ref and sum_byref on the other hand lead to a more imperative calling style, where temporary variables need to be declared to hold (references to) the intermediate results.

// composing sum examples (imperative)
> let r3a = ref 0;;
val r3a : int ref = {contents = 0;}
> let r3b = ref 0;;
val r3b : int ref = {contents = 0;}
> let r3c = ref 0;;
val r3c : int ref = {contents = 0;}
> sum_ref (1,1,r3a);;
val it : unit = ()
> sum_ref (2,2,r3b);;
val it : unit = ()
> sum_ref (!r3a,!r3b,r3c);;
val it : unit = ()
> let c3 = !r3c;;
val c3 : int = 6

> let mutable r4a = 0;;
val mutable r4a : int = 0
> let mutable r4b = 0;;
val mutable r4b : int = 0
> let mutable c4 = 0;;
val mutable c4 : int = 0
> sum_byref (1,1,&r4a);;
val it : unit = ()
> sum_byref (2,2,&r4b);;
val it : unit = ()
> sum_byref (r4a,r4b,&c4);;
val it : unit = ()
> c4;;
val it : int = 6

If you had obtained a library providing sum_ref but you wanted to code in a more natural (in F#) functional style it is easy to “wrap” sum_ref to give for example the same interface as nag_curried.

// mysum declaration and use
> let  mysum a b =
   let r = ref 0
   sum_ref(a,b,r)
   !r ;;
val mysum : int -> int -> int

> let c5=mysum(mysum 1 1) (mysum 2 2);;
val c5 : int = 6

Having looked at the toy “sum” example, we'll move on to look at some real examples from the NAG Library for .NET.

NAG Library for .NET

Firstly some details to reference the NAG Library. The #r syntax is only used for the interactive interpreter. For the F# compiler, command-line arguments or the usual Visual Studio reference settings are used instead. Also “open” the System and NagLibrary namespaces to avoid having to use fully qualified names on each method call.

// NAG Library reference for fsi
> #if INTERACTIVE
#I @"c:\Program Files\NAG\DTW02"
#r "NagLibrary32.dll"
#endif
open System
open NagLibrary
--> Added 'c:\Program Files\NAG\DTW02' to library include path
--> Referenced 'c:\Program Files\NAG\DTW02\NagLibrary32.dll'

A00: Licence Check Example

First call the simplest function in the library, that just returns true if a valid NAG licence is detected.

// a00ac example
> printfn "Have a NAG licence: %b" (A00.a00ac())
Have a NAG licence: true
val it : unit = ()

While this is a very simple example, it shows many of the advantages of the functional style and the top level interactive loop. Similar to MATLAB, the F# interface allows access to the NAG library functionality with the absolute minimum of additional syntax or programming steps. No main program, no explicit variable declarations, no explicit compilation steps etc.

D01: Quadrature Example

Next we take a slightly more complicated example from the Quadrature chapter. The method integrates the supplied function between the specified bounds, returning extra information about the number of iterations and accuracy. While it is straightforward to call this method, the values returned by byref parameters, and the need to explicitly cast the function to be integrated to the delegate type mean that the style resembles sum_byref above rather than the more idiomatically functional sum_curried.

Just as an example, two styles of setting up the parameters by reference are used. The classic ML style of defining values of reference type, which are dereferenced using !, and an alternative syntax (for npts) using an explicitly mutable variable which acts more like variables in imperative languages, in which the dereferencing is automatic.

// d01ah example: direct call
> let if1 = ref 0
let mutable npts=0
let relerr= ref 0.0
let f x = Math.Sin(x:double)
let nlimit=1000
let ff= D01.D01AH_F(f)
let result1 = D01.d01ah(
               0.0,Math.PI,0.01,&npts,relerr,ff,nlimit, if1);;
val mutable npts : int = 7
val relerr : float ref = {contents = 0.0006944567037;}
val f : float -> float
val nlimit : int = 1000
val ff : D01.D01AH_F
val result1 : float = 2.0
> !if1;;
val it : int = 0
> npts;;
val it : int = 7
> !relerr;
val it : float = 0.0006944567037

F# has some facilities to automatically present output parameters in a more functional style. If parameters passed by reference appear at the end of the .NET signature of a method, F# provides an alternative signature where the reference parameters may be omitted from the method call, and the returned results are provided as a list of values. F# will also implicitly apply a delegate constructor if the method is passed a compatible anonymous function (lambda expression), even though it will not automatically cast a variable bound to a function to the appropriate delegate type.

In this case, we may omit the final ifail parameter, whose value (0) is returned as the second item in the returned sequence rather than being captured by a reference parameter (ifl in the above example). However the position of the input parameter nlimit prevents this automatic system being used to avoid using explicit references for npts. Also rather than passing the variable ff, of type D01.D01AH_FC an anonymous function is used.

// d01ah example: returning a tuple
> let (result2,if2) = D01.d01ah(
                      0.0,Math.PI,0.01,&npts, relerr,(fun x -> f x),nlimit);;
val result2 : float = 2.0
val if2 : int = 0
> npts;;
val it : int = 7
> !relerr;;
val it : float = 0.0006944567037

As with the mysum example above, if this method is to be called often, a more naturally functional interface may be prefered.

The exact choice of interface depends a lot on personal requirements, but also personal aesthetic judgments. In the example below I've used a curried form for the input parameters, and a record type to capture the output fields, but for other uses one may use a tuple form for input and capture the results as a tuple (or by the use of out parameters).

// declaration of myd01ah: curried, returning a record
> type d01ahresults = {result: float ; npts: int ; relerr: float; ifail: int}

> let myd01ah f interval epsr nlimit =
    let ff=D01.D01AH_F(f)
    let (a,b) = interval
    let npts = ref 0
    let relerr = ref 0.0
    let ifl = ref 0
    let result = D01.d01ah(a,b,epsr,npts,relerr,ff,nlimit,ifl)
    {result= result; npts= !npts;relerr= !relerr;ifail= !ifl} ;;
val myd01ah :
  (float -> float) -> float * float -> float -> int -> d01ahresults 

Having set up this method we may directly integrate Math.Sin over the specified interval without the need to define any subsidiary reference or delegate objects. So the entire d01ah example program collapses into one line.

// using myd01ah
> myd01ah Math.Sin (0.0,Math.PI) 0.01 1000 ;;
val it : d01ahresults = {result = 2.0;
                         npts = 7;
                         relerr = 0.0006944567037;
                         ifail = 0;}

E04: Optimization Example

Finally, a more complicated example from the optimization chapter. The callback function that must be supplied has reference parameters, and again there are several reference parameters for the top level method.

The style used here is similar to that used for the D01 example, a curried form for input parameters, and a record type to capture the results. In addition pairs of float parameters in the original interface have been combined into a single input parameter and a single result field, denoting intervals.

// declaration of mye04ab: curried, returning a record
> type  e04abresults = { minimum: float ; x: float; bounds: (float*float); 
                       iter: int; ifail: int }
 
> let mye04ab f interv  e1 e2  mc =
    let a,b = interv
    let ra = ref a
    let rb = ref b
    let fx = ref 0.0
    let x = ref 0.0
    let mcr = ref mc
    let ifr = ref 0
    E04.e04ab((fun x res -> res <- f x),
               ref e1, ref e2, ra, rb, mcr ,x, fx ,ifr)
    {minimum = !fx; x = !x;bounds = (!ra,!rb); iter= !mcr; ifail = !ifr} ;;
val mye04ab :
  (float -> float) -> float * float -> float -> float -> int -> e04abresults

Again, once this method is defined, the minimization method can be called directly without having to set up any reference variables or delegates.

// using mye04ab
> mye04ab (fun x ->  (Math.Sin x) / x) (3.0,5.0) 0.0 0.0 30 ;;
val it : e04abresults = {minimum = -0.2172336282;
                         x = 4.493409455;
                         bounds = (4.493409397, 4.493409513);
                         iter = 10;
                         ifail = 0;}

Printed Output

The methods in the NAG Library for .NET typically return results via reference parameters (or return values of functions) however text can be directed to an output stream in the following situations:

  • The errors and warnings raised by the library will not throw a .NET exception. Instead the method will return with a non zero ifail value. As described in the Introduction to the Library, the display of the warnings may be controlled by setting the Warning property of the PrintManager class appropriately.
  • Certain methods in the library have facilities to display monitoring information. In some cases this monitoring is controlled by a user supplied monitoring function. The C# example programs provided with the library use monitoring callback methods that use Console.WriteLine however the user supplied method may direct the monitoring information to any suitable destination, for example a TextBox in a windows form application. In other cases, monitoring is controlled by integer or boolean flags to enable the monitoring, in this case, final destination stream may be controlled as for warnings, by setting the Message property on teh Printmanager class.

The next two examples use a windows form application (derived from a copy of the sample form in the F# sample distribution from Microsoft).

Monitoring Function (e04cb example)

e04cb is an example of a method that takes a user supplied method to monitor the progress of the iteration. We define a small F# wrapper as before (although this time returning a tuple of values rather than a record of a named record type).

// declaration of  mye04cb

let mye04cb n x tolf tolx func monit maxcal =
    let ffunc = new E04.E04CB_FUNCT(
                     fun n xc (res:byref<float>) -> res <- func xc)
    let fmonit = new E04.E04CB_MONIT(monit)
    let ifl = ref 0
    let rf = ref 0.0
    E04.e04cb(n,x,rf,tolx,tolf,ffunc,fmonit,maxcal,ifl)
    (x,!rf)

We then define the function to be minimised, and the initial bounds on the variable.

// object function for e04cb example

let mutable e04cbf = fun (xc: float[]) ->
    Math.Exp(xc.[0]) * (4.00e0 * xc.[0] * (xc.[0] + xc.[1]) +
    2.00e0 * xc.[1] * (xc.[1] + 1.00e0) +
    1.00e0);
// e04cb example bounds

let mutable e04cbx = [|-1.0;1.0|]

In this example we will use a simplified monitoring function that only prints the number of iterations. As we are using a windows form application we don't want to write to the console. the form has a TextBox declared (textB) and we want the monitoring function to update the text property of that box:

// e04cb monit function

let e04cbmonitor  fmin fmax sim n ncall se vr =
       textB.Text <- ( textB.Text +
                     (sprintf " There have been %d function calls\n" ncall))

When the "Run Example 1" menu option is chosen, the runexmpl1 method is executed:

// run the e04cb example

let runexmpl1 () = 
       textB.BackColor<- Drawing.Color.White
       textB.Text <- "monitor\n"
       textB2.Text <- sprintf "The final function value is ...\n"
       let (interv,vl) = mye04cb  2 e04cbx (Math.Sqrt(X02.x02aj())) 
                                 (Math.Sqrt(Math.Sqrt(X02.x02aj())))
                                  e04cbf
                                  e04cbmonitor
                                  100
       textB2.Text <- ( textB2.Text + (sprintf "  %f \n" vl))

As can be seen, this just initializes the text in the two text boxes, calls mye04cb and then finally retrieves the reference to the minimum value and updates the results text box. the monitoring text box will have been updated during the progress of the iteration by e04cbmonitor

fsharp form executed from Visual Studio

If the form is executed by the F# interpreter (fsi command line or the F# interactive window in Visual Studio) then we can make use of the above mutable definitions to change the function to be minimized without restarting the form application. Entering (for example):

// Update e04cb object function

e04cbf <- fun (xc: float[]) -> 1.0;;

At the interactive prompt will cause the variable e04cbf to be updated (to represent the constant function 1) re-selecting the “Run e04cb example” menu option will cause e04cb to be re-executed using this object function (finding the minimum value of 1). Future versions of F# may expose the interpreter as an eval function (as in lisp and some other functional languages) which would avoid the need to maintain an open interpreter window, however use of the interpreter in this way is still quite a powerful way of interacting with the system,

Internal Monitoring (e04xa example)

Some methods in the library do not take a user supplied monitoring function, but instead handle the monitoring internally, often controlled by an integer parameter (or optional parameter) that controls verbosity of the output. By default this monitoring information will be sent to System.Console.WriteLine however as described above it may be sent to a more appropriate stream, or as shown below to a textbox. We take e04xa as a simple example of such a function.

// declaration of  mye04xa

let mye04xa mlevel n epsrf x mode objfun hforw =
    let objf = ref 0.0
    let objgrd :float array = Array.zeroCreate n
    let hcntrl :float array = Array.zeroCreate n
    let h :float [,] = Array2D.zeroCreate n n
    let info : int array = Array.zeroCreate n
    let mref = ref mode
    let objfref = ref 0.0
    let warnref = ref 0
    let ifailref = ref 0
    let objfund = E04.E04XA_OBJFUN(
                   fun (a:byref<int>) b c (d:byref<float>) e f -> 
                    d <- objfun a b c d e f
                    )
    E04.e04xa (mlevel,n,epsrf,x,mref,objfund,hforw,objfref,objgrd,
               hcntrl,h,warnref,info,ifailref)
    (!objfref,objgrd,hcntrl,h,!warnref)
// e04xa object function

let e04xaobjfun int n (x: float array) objf objgrd nstate =
  let a = x.[0] + 10.0*x.[1]
  let b = x.[2] - x.[3]
  let c = x.[1] - 2.0*x.[2]
  let d = x.[0] - x.[3]
  a*a + 5.0*b*b + c*c*c*c + 10.0*d*d*d*d

This time when the “Run e04xa” menu option is chosen, the following method is executed

// run the e04xa example

// make mode a parameter just so we can force an error to occur

// 0 is a valid but 10 is not a valid input value for mode.

let runexmpl2 (mode) = 
       textB.BackColor<- Drawing.Color.White
       textB.Text <- "monitor\n"
       textB2.Text <- sprintf "The final function value is ...\n"
//  Beta 2 code needed to redirect Console.Out
//  Now we can use PrintManager properties.
//      let oldOut = Console.Out
//       let strWriter = new IO.StringWriter()
//       Console.SetOut(strWriter);

       PrintManager.Message <- (fun s -> textB.Text <- textB.Text + s  + "\n")
       PrintManager.Warning <- (fun s -> 
                                 textB.BackColor<- Drawing.Color.Red
                                 textB.Text <- textB.Text + "\nError:\n" + s   + "\n")

       let (objf,z1,z2,z3,z4)=  
           mye04xa
             (*mlevel*) 10 
             (*n*) 4
             (*epsrf*) 0.0
             (*x*) [|3.0;-1.0;0.0;1.0|]
             (*mode*) mode 
             (*objfun*) e04xaobjfun
             (*hforw*) [|-1.0;-1.0;-1.0;-1.0|]
//       Console.SetOut(oldOut)
//       textB.Text <- strWriter.ToString()

       textB2.Text <- ( textB2.Text + (sprintf "  %f \n" objf))

F# Files

nagfsharp1.fsx: F# file including all the Console Application code shown above. Note: if this is used in an F# Interactive session (Control-Alt-F in Visual Studio) it references c:\Program Files\NAG\DTW02\NagLibrary32.dll. You will need to adjust the Include directives if the library is installed at a different location.

nagfsharp2.fsx: F# file including the full code for a windows form application, with a drop down menu giving the option to run two example programs with monitoring enabled. This is essentially the “Hello World” Form Example from the F# sample distribution from Microsoft, extended with the code to run NAG examples, as shown in the previous section. Note: if this is used in an F# Interactive session (Control-Alt-F in Visual Studio) it references c:\Program Files\NAG\DTW02\NagLibrary32.dll. You will need to adjust the Include directives if the library is installed at a different location.

nagfsharp3.fsx: An additional example, from Sorin Seban, giving the e04uc example program as F# code.

Conclusions

This article has give examples showing how to call the NAG Library for .NET from the interactive top level loop of F#, and in particular how writing small functions around the supplied methods can result in greatly simplified calling conventions.

It has been asked whether it would be possible for the supplied .NET methods to be more F#-like. It would be possible for example to place all out or ref parameters at the end of the method parameter list, however this wouldn't always lead to the most natural interface in C# or VB.NET, and F# users would perhaps still want to make similar wrappers to avoid the need to explicitly declare delegates, or to use named record types for output, or curried forms for input as in the examples above.