A Software Engineering Blog

by Nick Holmes

  Home  |   Contact  |   Syndication    |   Login
  11 Posts | 0 Stories | 6 Comments | 0 Trackbacks

News

Archives

Post Categories

Tuesday, May 05, 2009 #

I had half an hour to fill while I waited for a large download, on my slow connection. I'd thought about re-implementing my C# WCF test host in F#. It didn't look too complex, and indeed it wasn't:

#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\"
#r "System.ServiceModel.dll"
#r "Server.dll"
open System
open System.ServiceModel
open System.Diagnostics
open Coyote.FSWCFTest

let services =

    [ (typeof<TestWebService>, "http://localhost:8080/Test/FSWCFTest.svc") ]

let logException (msg, exn:Exception) =
    Trace.TraceWarning(msg)
    Trace.WriteLine(exn.Message)
    Trace.WriteLine(exn.Source)

let startHost (serviceType:Type, url) =
    try
        let uri = [| new Uri(url) |]
        let host = new ServiceHost(serviceType, uri)
        host.Open()
        Some(host)
    with
    | e -> logException ("Exception thrown starting service.", e)
           None

let stopHost (host: ServiceHost option)  =
    try
        match host with
        | None -> ()
        | Some(host) ->
            if host.State <> CommunicationState.Closed then
                host.Close()
                Trace.WriteLine("Service Stopped")               
    with
    | e -> logException ("Exception thrown stopping service.", e)

let showHostStatus (host: ServiceHost option) =
    match host with
    | Some(hst) ->
        let strdots = new String ( '.', 40 - hst.Description.Name.Length);
        Console.ForegroundColor <- match hst.State with
                                   | CommunicationState.Opened -> ConsoleColor.Green
                                   | _ -> ConsoleColor.Red        
        Console.WriteLine("{0} service{1}{2}", hst.Description.Name,

            strdots, hst.State.ToString())
    | None -> Console.ForegroundColor <- ConsoleColor.Red
              Console.WriteLine("Service failed to start.")

let main =
    Console.Title <- "Server Test Console"
    Console.BackgroundColor <- ConsoleColor.DarkBlue
    Console.WindowWidth <- 120
    Console.Clear()
    Console.WriteLine("Server Test Console")
    Console.WriteLine("Copyright 2008 Coyote Software, GmbH.")
    Console.WriteLine()
    let hosts = services |> List.map startHost
    let mutable quit = false
    while not quit do
        let inp = Console.ReadLine()  
        let inpClean = inp.Trim().ToLower()
        match inpClean with
        | "exit"   -> quit <- true
        | "cls"    -> Console.Clear()
        | "status" -> let cc = Console.ForegroundColor
                      Console.WriteLine("Status at {0} is", DateTime.Now)
                      hosts |> List.iter showHostStatus
                      Console.ForegroundColor <- cc      
        | "stop"   -> hosts |> List.iter stopHost
        | _        -> Console.WriteLine("Unknown command {0}", inp)
    done

This implementation is about half the size of the C# implementation, although the original has a couple of extra commands. I preferred Console.WriteLine to printfn, as I have used other Console methods, and I think the code is a little clearer.

One improvement to this app would be to have is use reflection to automatically find all  the services in the assembly (rather than require the list to be set up), but I've been using the C# version almost daily for over a year, and its good enough like this.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

I tidied up the F# web service, mainly by factoring out an interface for the web service. Without the attributes it looks like this:

type ITestWebService =
    abstract TestMethod: Param:string -> string
type TestWebService() =
    interface ITestWebService with
        member x.TestMethod s = "Hello " + s;

However, I noticed when I was setting up the C# host, I needed to cast to get to access the interface, like this:

TestWebService tws = new TestWebService();
ITestWebService itws = tws as ITestWebService;

Neither of these far more obvious ways to access the member work:

tws.TestMethod("test");                     // Doesn't compile
tws.ITestWebService.TestMethod("test");     // Doesn't compile

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

For all the power and flexibility that WCF provides, creating a basic web service in C# is easy enough. Essentially, it's just a POCO adorned with some special attributes. Doing the same thing in F#, then, should also be easy enough. I tried this:

#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\"
#r "System.ServiceModel.dll"

open System.ServiceModel

[<ServiceContract(ConfigurationName = "TestWebService", Namespace = "http://coyote-software.com/FSWCFTest")>]
[<ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)>]
type public TestWebService =
    class

        [<OperationContract>]
        member public x.TestMethod(s) = "Hello " + s;
    end

Essentially, I've referenced the WCF assembly, and created a class with a single method, and added the needed ServiceContract, ServiceBehavior and OperationContract attributes. I compiled this into to a dll.

To test this, I needed to host it somewhere. I already have a console host application in C#, and so I used that for testing, and got this exception:

The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor.

Constructors in F# are a little different to C#, and a bit of hunting through the spec, and I had my solution:

type public TestWebService() =

Just a pair of missing parenthesis! This was going extremely well, so the next task is to call the method. For this we need to generate a client proxy with svcutil.exe. This generates C# code, but no reason not to use this, driven from an F# client. I compiled up the generated C# into a dll, and then referenced that from a simple F# console client:

#light
#I @"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\"
#I @"c:\Development Projects\Research\FSWCF\Client\bin\debug\"
#r "System.ServiceModel.dll"
#r "client.dll"
open System

do
    let service = new TestWebServiceClient()
    let retVal = service.TestMethod "Nick"
    printfn "%s" retVal
    Console.ReadLine() |> ignore

This resulted in "Hello Nick" on the console. It was extremely simple to get this (albeit trivial) web service running.

What I've not done yet is pass a more complex data contract, but that will come with in the next step, using LINQ-to-Sql to grab some data, and pass that back to the client.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

I previously said that C#’s lambda functions were not curried, and it wasn’t possible to partially apply them. However, it’s usually possible to manually curry functions, if you need to. Here is an example:

static void Main(string[] args)
{
    int t = f(1)(3)(5)(7);

    Console.WriteLine("{0}", t);

    var g = f(1);
    var h = g(3);
    var i = h(5);
    int j = i(7);

    Console.WriteLine("{0}", j);
}

static Func<int, Func<int, Func<int, int>>> f(int a)
{
    return (b => c => d => (a + b + c + d));
}

It’s interesting to step through that code in Visual Studio. As the complex lambda expression is repeatedly returned to, the highlighting outlines exactly which sub-function is being evaluated. However, the return type of the f is not at all easy to read (although the new C# 3.0 var keyword means we don’t need to repeat this horror for g, h, & i). The equivalent code in F# is far more svelte:

let f a b c d = a + b + c + d

Even with my cryptically short function name, its clear what this function does. There’s one more thing on curried functions I want to look at, but before that I’m going to look at implementing Web Services in F# and WCF.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

All this currying and partial application stuff is all very interesting, but surely its has to have some kind of run-time performance hit. What if I just want to keep things straightforward?

Firstly, if we have a function that takes only a single argument, there is nothing to curry. It makes no sense to call a function with no arguments, so your only option is to make the exact call.

That in mind, we can do this:

let repeat(str, n) = ...

That syntax is sure to catch out C# programmers (like me), because it looks a lot like a normal C# function call. You might not even register, at first glance, the extra parenthesis around the arguments. However, these parenthesis are nothing to do with the function syntax, but everything to do with tuples:

let name = ("Fred", "Smith")

here, name is equal to the pair of values “Fred” and “Smith”. Tuples can have more than 2 components. The type is reported as:

val x : string * string

Personally, I find that * as the separator a bit jarring, but I assume there is a good reason to use it in preference to “,” - maybe it will come to light some day.

Anyway, a tuple is a simple data structure that allows you to group 2 or more components into a single argument, and thereby create functions that need not be curried.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

In my last two posts, I described how F# transforms functions with more than one argument into chains of functions with a single argument. Strictly speaking, all functions in F# must have exactly one argument, and return exactly one result.  There is a special type, unit, which can be used as a dummy when no argument or return is required, like void in C#.

F#’s functions are lambda functions, formally described by lambda calculus which provides the theoretic model for functional languages. Happily, we don’t all need to be fluent in lambda calculus to use F#. The F# compiler automatically converts functions to these chains of lambda functions in a process called currying. The resulting function is said to be curried - but remember the resulting function is just the first in the chain. The term is named for Haskell Curry - for whom the Haskell language is also named (indeed there is another language called Curry too).

Incidently C#’s lambda expressions are not curried automatically curried, and so its not possible to partially apply them.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

OK, so you define a function that takes 2 parameters, but you actually get a function that takes 1 parameter, and returns a function that will take the second parameter and return the final result. Hmm, this raises lots of questions.

What happens if the function has more than two parameters?

>let f a b c = a + b + c

is of type

val f : int -> int -> int -> int

So we get a chain of functions, each one taking exactly one parameter, and returning a function that takes the next.

If there are more that 2 parameters, can I partially apply more than one at a time?

Following on from above, we can do:

>let g = f 1 2

val g : (int -> int)

>g 3

val it : int = 6

This looks like F# functions can just accept a subset of their arguments, but remember that as f returns a function, what is really happening is the equivalent of this:

let g = (f 1) 2

We are making a sequence of function calls. We could make the exact call like this:

((f 1) 2) 3

The consequence of this is that we can’t partially apply any sub-set of the arguments. We still have to call the function chain in the correct order, which partially apply the arguments strictly from left to right.

What happens to the partially applied arguments?

They are captured forever and immutably in the returned function.

let f a b = a + b

let g = f 1

let h = f 10

g will always return its argument plus 1, h always plus 10. f did not return the same function when called with different arguments.

Strange as this last point seems to those of us more used to C#, this notion of capturing values into functions does exist in C#. Anonymous delegates capture the values of variables from their declaring method. In C# 3.0, lambda functions are a simpler syntax for these anonymous delegates. Here is an example.

static void Main(string[] args)
{
    var g = f(1);
    var h = f(10);

    Console.WriteLine(”g(5) = {0}”, g(5));
    Console.WriteLine(”h(5) = {0}”, h(5));
    Console.WriteLine(”f(3)(5) = {0}”, f(3)(5));
}

static Func<int, int> f(int a)
{
    return new Func<int, int>(x => x + a);
}

Similar result, ugly code!

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati

I’ve been spending some time recently looking at F# - I have a specific task in mind to which F# seems very well suited, so the motivation is there! After many years doing C then C++ and now C#, it’s easy to fall into the trap of thinking some things work just the same in F#.

One example of this is functions. I was happily experimenting with some code, thinking I was getting the measure of F#, but one small detail kept catching my eye - the very strange types reported for functions.

It all starts off simple enough - when you assign an expression to a value in F# Interactive, it reports back with the type it has inferred:

>let myStr = "Hello World"
val myStr : string

Simple enough. Now what happens if we create a function:

>let toStr n = sprintf "%d" n;;
val toStr : int -> string

This makes perfect sense too, as we’ve created a function that takes an int and returns a string.

Now lets add a second argument:

>let makeTable n v = [| for i in 0..n -> v*i |];;
val makeTable : int -> int -> int array

Initially, I could not see why F# reported the function type in such an unusual way. The function takes two arguments and returns an array, but the reported type reads “a function that takes an int and returns a function that takes an int and returns an array“. Why so complex? If this was true, could we call the function with a single argument, and expect a new function back, like this…

>let partTable = makeTable 10;;

Yes! that works:

val partTable : (int -> int array)

When we call this function, its captured the first parameter, and completes as expected:

>partTable 9;;
val it : int array [|0; 9; 18; 27; 36; 45; 54; 63; 72; 81; 90|]

More on this to come.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati