Welcome to Gordon Hogenson's F# Blog

I'm the technical writer who wrote most of the MSDN documentation for F#, and I decided to start a less formal channel of communication to share some of what I'm learning about F# and associated technologies.

But first a few notes about how to let me know about problems and other feedback for the F# MSDN docs.  First to clarify what I actually am responsible for.  Anything with an address that includes msdn.microsoft.com/library and is related to F#, I am interested in hearing feedback on.  In terms of the specific table of contents areas in the MSDN TOC, that is anything under this node: https://msdn.microsoft.com/en-us/library/dd233154.aspx.  The feedback link is harder to find in MSDN's lightweight view, but it is there at the very bottom of the page.  Any comments you put into the feedback box will make it to me, unless it gets caught up in the spam filter, which it shouldn't unless you are using the feedback link to advance your Viagra business.

One of the things that this blog will include is lots of F# programs!  In the course of my responsibilities, I often write small pieces of code, and sometimes larger projects.  Much of this is an effort to explore the ins and out of some particular aspect of the F# language and the F# core library.  For example, over the past year, I've written some examples using F#'s asynchronous workflows, the F# MailboxProcessor, and the like.

The other thing that I'm interested in is the transition from other languages, like C++ and C#, to F#.  As a C++ and C# programmer, I am familiar with a certain paradigm of computing, but I also was vaguely familiar with the idea of functional programming.  Over the last several years, I've had the opportunity to explore the functional programming paradigm, and I'm interested in how this changes the way we think about solving everyday programming problems and how this way of thinking might improve how I design new APIs.  For example, how do I code without using mutable variables?  And maybe more importantly, when is it beneficial to code without mutable variables, and when is it being too pedantic?

And then there are the larger software engineering questions, such as, can adopting a functional approach improve the ability of a team to deliver great products?  The promise of functional programming of greatest interest to those who run software businesses is that it makes it easier to write code that is stable and is easier to maintain.  One of the larger things that we at Microsoft are learning in embracing a functional language like F# is how using this type of programming can benefit our industry.

To get us warmed up, I'll say that I've been looking at the MailboxProcessor lately.  The F# MailboxProcessor provides a message-passing mechanism that allows you to structure a program as a set of agents which read and respond to a queue of messages.  In some ways it is akin to MSMQ, but its inspiration comes from the language Erlang, which is specifically designed to be an agent-based language.  F# is not specifically designed for agent-based programming, but the MailboxProcessor provides support for this type of programming.

For example here is a program I wrote recently that starts up a MailboxProcessor. The code defines an agent that runs a loop that reads messages.  Here, the message is just a string read from the console window, paired with a reply channel.  The agent reads each message and then submits a reply through a reply channel that is passed in.  The reply is then printed, or if the special "Stop" command is given by the user, the loop ends.

MailboxProcessorTest1.fs

module MailboxProcessorTest1 =

 

    open System

 

    type Message = string * AsyncReplyChannel<string>

 

    let formatString = "Message number {0} was received. Message contents: {1}"

 

 

    let agent = MailboxProcessor<Message>.Start(fun inbox ->

        let rec loop n =

            async {

                    let! (message, replyChannel) = inbox.Receive();

                    if (message = "Stop") then

                        replyChannel.Reply("Stopping.")

                    else

                        replyChannel.Reply(String.Format(formatString, n, message))

                    do! loop (n + 1)

            }

        loop 0)

 

    printfn "Mailbox Processor Test"

    printfn "Enter some text and hit ENTER to submit a message."

    printfn "Type 'Stop' to terminate."

 

    let mutable stop = false

    while (not stop) do

        printf "> "

        let input = Console.ReadLine()

        let reply = agent.PostAndReply(fun replyChannel -> input, replyChannel)

        if (reply = "Stopping.") then

            stop <- true

        printfn "Reply: %s" reply

 

 

 

    printfn "Press enter to continue."

    Console.ReadLine() |> ignore

 

 One thing I try to do in the documentation is demonstrate how to use functional programming style.  Functional programming purists might prefer to rewrite the loop as a recursive function, and eliminate the mutable control variable.

    let rec loop() =

        printf "> "

        let input = Console.ReadLine()

        let reply = agent.PostAndReply(fun replyChannel -> input, replyChannel)

        if (reply <> "Stopping.") then

            printfn "Reply: %s" reply

            loop()

        else

            ()

    loop()

But as a practical person, I now worry, will my recursive function create a stack frame for every iteration, or is F# going to be smart and just reuse the same stack frame for it?  If I was confident enough in my knowledge of tail recursion and the F# compiler's tail recursion features, I could deduce all this from the code, but then to be sure I might want to check empirically, so I fired up the debugger and set a breakpoint in the loop, then went through a few iterations on input.  In fact, the call stack window shows that there is only one stack frame that is shared for each recursive call.  Great, now I know this "functional" form of my code won't blow up the stack.

 

That's it for today, but clearly the code could be improved.  What about adding a timeout and handling what happens then?  In the next installment, I will look at how to do this.

Gordon