layout: post
title: “Twenty six low-risk ways to use F# at work”
description: “You can start right now — no permission needed”
categories: []
seriesId: “Low-risk ways to use F# at work”
seriesOrder: 1


So you’re all excited about functional programming, and you’ve been learning F# in your spare time,
and you’re annoying your co-workers by ranting about how great it is, and you’re itching to use it for serious stuff at work…

But then you hit a brick wall.

Your workplace has a “C# only” policy and won’t let you use F#.

If you work in a typical enterprise environment, getting a new language approved will be a long drawn out process,
involving persuading your teammates, the QA guys, the ops guys, your boss, your boss’s boss, and the mysterious bloke down the hall who you’ve never talked to.
I would encourage you to start that process (a helpful link for your manager), but still, you’re impatient and thinking “what can I do now?”

On the other hand, perhaps you work in a flexible, easy going place, where you can do what you like.

But you’re conscientious, and don’t want to be one of those people who re-write some mission critical system in APL, and then vanish without trace, leaving
your replacement some mind-bendingly cryptic code to maintain.
No, you want to make sure that you are not doing anything that will affect your team’s bus factor.

So in both these scenarios, you want to use F# at work, but you can’t (or don’t want to) use it for core application code.

What can you do?

Well, don’t worry! This series of articles will suggest a number of ways you can get your hands dirty with F# in a low-risk, incremental way, without affecting any critical code.

Series contents

Here’s a list of the twenty six ways so that you can go straight to any one that you find particularly interesting.

Part 1 - Using F# to explore and develop interactively

1. Use F# to explore the .NET framework interactively

2. Use F# to test your own code interactively

3. Use F# to play with webservices interactively

4. Use F# to play with UI’s interactively

Part 2 - Using F# for development and devops scripts

5. Use FAKE for build and CI scripts

6. An F# script to check that a website is responding

7. An F# script to convert an RSS feed into CSV

8. An F# script that uses WMI to check the stats of a process

9. Use F# for configuring and managing the cloud

Part 3 - Using F# for testing

10. Use F# to write unit tests with readable names

11. Use F# to run unit tests programmatically

12. Use F# to learn to write unit tests in other ways

13. Use FsCheck to write better unit tests

14. Use FsCheck to create random dummy data

15. Use F# to create mocks

16. Use F# to do automated browser testing

17. Use F# for Behaviour Driven Development

Part 4. Using F# for database related tasks

18. Use F# to replace LINQpad

19. Use F# to unit test stored procedures

20. Use FsCheck to generate random database records

21. Use F# to do simple ETL

22. Use F# to generate SQL Agent scripts

Part 5: Other interesting ways of using F#

23. Use F# for parsing

24. Use F# for diagramming and visualization

25. Use F# for accessing web-based data stores

26. Use F# for data science and machine learning

(BONUS) 27: Balance the generation schedule for the UK power station fleet

Getting started

If you’re using Visual Studio, you’ve already got F# installed, so you’re ready to go! No need to ask anyone’s permission.

If you’re on a Mac or Linux, you will have to a bit of work, alas (instructions for Mac and Linux).

There are two ways to use F# interactively: (1) typing in the F# interactive window directly, or (2) creating a F# script file (.FSX) and then evaluating code snippets.

To use the F# interactive window in Visual Studio:

  1. Show the window with Menu > View > Other Windows > F# Interactive
  2. Type an expression, and use double semicolon (;;) to tell the interpreter you’re finished.

For example:

  1. let x = 1
  2. let y = 2
  3. x + y;;

Personally, I prefer to create a script file (File > New > File then pick “F# script”) and type code there, because you get auto-complete and intellisense.

Twenty six low-risk ways to use F# at work - 图1

To run a bit of code, just highlight and right click, or simply do Alt+Enter.

Twenty six low-risk ways to use F# at work - 图2

Working with external libraries and NuGet

Most of the code samples reference external libraries which are expected to be under the script directory.

You could download or compile these DLLs explicitly, but I think using NuGet from the command line is simpler.

  1. First, you need to install Chocolately (from chocolatey.org)
  2. Next install the NuGet command line using
    cinst nuget.commandline
  3. Finally, go to your script directory, and install the NuGet package from the command line.

    For example, nuget install FSharp.Data -o Packages -ExcludeVersion

    As you see, I prefer to exclude versions from Nuget packages when using them from scripts so that I can update later without breaking existing code.

Part 1: Using F# to explore and develop interactively

The first area where F# is valuable is as a tool to interactively explore .NET libraries.

Before, in order to do this, you might have created unit tests and then stepped through them with a debugger to understand what is happening.
But with F#, you don’t need to do that, you can run the code directly.

Let’s look at some examples.

1. Use F# to explore the .NET framework interactively

The code for this section is available on github.

When I’m coding, I often have little questions about how the .NET library works.

For example, here are some questions that I have had recently that I answered by using F# interactively:

  • Have I got a custom DateTime format string correct?
  • How does XML serialization handle local DateTimes vs. UTC DateTimes?
  • Is GetEnvironmentVariable case-sensitive?

All these questions can be found in the MSDN documentation, of course, but can also answered in seconds by running some simple F# snippets, shown below.

Have I got a custom DateTime format string correct?

I want to use 24 hour clock in a custom format. I know that it’s “h”, but is it upper or lowercase “h”?

  1. open System
  2. DateTime.Now.ToString("yyyy-MM-dd hh:mm") // "2014-04-18 01:08"
  3. DateTime.Now.ToString("yyyy-MM-dd HH:mm") // "2014-04-18 13:09"

How does XML serialization handle local DateTimes vs. UTC DateTimes?

How exactly, does XML serialization work with dates? Let’s find out!

  1. // TIP: sets the current directory to be same as the script directory
  2. System.IO.Directory.SetCurrentDirectory (__SOURCE_DIRECTORY__)
  3. open System
  4. [<CLIMutable>]
  5. type DateSerTest = {Local:DateTime;Utc:DateTime}
  6. let ser = new System.Xml.Serialization.XmlSerializer(typeof<DateSerTest>)
  7. let testSerialization (dt:DateSerTest) =
  8. let filename = "serialization.xml"
  9. use fs = new IO.FileStream(filename , IO.FileMode.Create)
  10. ser.Serialize(fs, o=dt)
  11. fs.Close()
  12. IO.File.ReadAllText(filename) |> printfn "%s"
  13. let d = {
  14. Local = DateTime.SpecifyKind(new DateTime(2014,7,4), DateTimeKind.Local)
  15. Utc = DateTime.SpecifyKind(new DateTime(2014,7,4), DateTimeKind.Utc)
  16. }
  17. testSerialization d

The output is:

  1. <DateSerTest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  2. <Local>2014-07-04T00:00:00+01:00</Local>
  3. <Utc>2014-07-04T00:00:00Z</Utc>
  4. </DateSerTest>

So I can see it uses “Z” for UTC times.

Is GetEnvironmentVariable case-sensitive?

This can be answered with a simple snippet:

  1. Environment.GetEnvironmentVariable "ProgramFiles" =
  2. Environment.GetEnvironmentVariable "PROGRAMFILES"
  3. // answer => true

The answer is therefore “not case-sensitive”.

2. Use F# to test your own code interactively

The code for this section is available on github.

You are not restricted to playing with the .NET libraries, of course. Sometimes it can be quite useful to test your own code.

To do this, just reference the DLL and then open the namespace as shown below.

  1. // set the current directory to be same as the script directory
  2. System.IO.Directory.SetCurrentDirectory (__SOURCE_DIRECTORY__)
  3. // pass in the relative path to the DLL
  4. #r @"bin\debug\myapp.dll"
  5. // open the namespace
  6. open MyApp
  7. // do something
  8. MyApp.DoSomething()

WARNING: in older versions of F#, opening a reference to your DLL will lock it so that you can’t compile it! In which case, before recompiling, be sure to reset the interactive session to release the lock.
In newer versions of F#, the DLL is shadow-copied, and there is no lock.

3. Use F# to play with webservices interactively

The code for this section is available on github.

If you want to play with the WebAPI and Owin libraries, you don’t need to create an executable — you can do it through script alone!

There is a little bit of setup involved, as you will need a number of library DLLs to make this work.

So, assuming you have got the NuGet command line set up (see above), go to your script directory, and install the self hosting libraries
via nuget install Microsoft.AspNet.WebApi.OwinSelfHost -o Packages -ExcludeVersion

Once these libraries are in place, you can use the code below as a skeleton for a simple WebAPI app.

  1. // sets the current directory to be same as the script directory
  2. System.IO.Directory.SetCurrentDirectory (__SOURCE_DIRECTORY__)
  3. // assumes nuget install Microsoft.AspNet.WebApi.OwinSelfHost has been run
  4. // so that assemblies are available under the current directory
  5. #r @"Packages\Owin\lib\net40\Owin.dll"
  6. #r @"Packages\Microsoft.Owin\lib\net40\Microsoft.Owin.dll"
  7. #r @"Packages\Microsoft.Owin.Host.HttpListener\lib\net40\Microsoft.Owin.Host.HttpListener.dll"
  8. #r @"Packages\Microsoft.Owin.Hosting\lib\net40\Microsoft.Owin.Hosting.dll"
  9. #r @"Packages\Microsoft.AspNet.WebApi.Owin\lib\net45\System.Web.Http.Owin.dll"
  10. #r @"Packages\Microsoft.AspNet.WebApi.Core\lib\net45\System.Web.Http.dll"
  11. #r @"Packages\Microsoft.AspNet.WebApi.Client\lib\net45\System.Net.Http.Formatting.dll"
  12. #r @"Packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll"
  13. #r "System.Net.Http.dll"
  14. open System
  15. open Owin
  16. open Microsoft.Owin
  17. open System.Web.Http
  18. open System.Web.Http.Dispatcher
  19. open System.Net.Http.Formatting
  20. module OwinSelfhostSample =
  21. /// a record to return
  22. [<CLIMutable>]
  23. type Greeting = { Text : string }
  24. /// A simple Controller
  25. type GreetingController() =
  26. inherit ApiController()
  27. // GET api/greeting
  28. member this.Get() =
  29. {Text="Hello!"}
  30. /// Another Controller that parses URIs
  31. type ValuesController() =
  32. inherit ApiController()
  33. // GET api/values
  34. member this.Get() =
  35. ["value1";"value2"]
  36. // GET api/values/5
  37. member this.Get id =
  38. sprintf "id is %i" id
  39. // POST api/values
  40. member this.Post ([<FromBody>]value:string) =
  41. ()
  42. // PUT api/values/5
  43. member this.Put(id:int, [<FromBody>]value:string) =
  44. ()
  45. // DELETE api/values/5
  46. member this.Delete(id:int) =
  47. ()
  48. /// A helper class to store routes, etc.
  49. type ApiRoute = { id : RouteParameter }
  50. /// IMPORTANT: When running interactively, the controllers will not be found with error:
  51. /// "No type was found that matches the controller named 'XXX'."
  52. /// The fix is to override the ControllerResolver to use the current assembly
  53. type ControllerResolver() =
  54. inherit DefaultHttpControllerTypeResolver()
  55. override this.GetControllerTypes (assembliesResolver:IAssembliesResolver) =
  56. let t = typeof<System.Web.Http.Controllers.IHttpController>
  57. System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
  58. |> Array.filter t.IsAssignableFrom
  59. :> Collections.Generic.ICollection<Type>
  60. /// A class to manage the configuration
  61. type MyHttpConfiguration() as this =
  62. inherit HttpConfiguration()
  63. let configureRoutes() =
  64. this.Routes.MapHttpRoute(
  65. name= "DefaultApi",
  66. routeTemplate= "api/{controller}/{id}",
  67. defaults= { id = RouteParameter.Optional }
  68. ) |> ignore
  69. let configureJsonSerialization() =
  70. let jsonSettings = this.Formatters.JsonFormatter.SerializerSettings
  71. jsonSettings.Formatting <- Newtonsoft.Json.Formatting.Indented
  72. jsonSettings.ContractResolver <-
  73. Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
  74. // Here is where the controllers are resolved
  75. let configureServices() =
  76. this.Services.Replace(
  77. typeof<IHttpControllerTypeResolver>,
  78. new ControllerResolver())
  79. do configureRoutes()
  80. do configureJsonSerialization()
  81. do configureServices()
  82. /// Create a startup class using the configuration
  83. type Startup() =
  84. // This code configures Web API. The Startup class is specified as a type
  85. // parameter in the WebApp.Start method.
  86. member this.Configuration (appBuilder:IAppBuilder) =
  87. // Configure Web API for self-host.
  88. let config = new MyHttpConfiguration()
  89. appBuilder.UseWebApi(config) |> ignore
  90. // Start OWIN host
  91. do
  92. // Create server
  93. let baseAddress = "http://localhost:9000/"
  94. use app = Microsoft.Owin.Hosting.WebApp.Start<OwinSelfhostSample.Startup>(url=baseAddress)
  95. // Create client and make some requests to the api
  96. use client = new System.Net.Http.HttpClient()
  97. let showResponse query =
  98. let response = client.GetAsync(baseAddress + query).Result
  99. Console.WriteLine(response)
  100. Console.WriteLine(response.Content.ReadAsStringAsync().Result)
  101. showResponse "api/greeting"
  102. showResponse "api/values"
  103. showResponse "api/values/42"
  104. // for standalone scripts, pause so that you can test via your browser as well
  105. Console.ReadLine() |> ignore

Here’s the output:

  1. StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
  2. {
  3. Date: Fri, 18 Apr 2014 22:29:04 GMT
  4. Server: Microsoft-HTTPAPI/2.0
  5. Content-Length: 24
  6. Content-Type: application/json; charset=utf-8
  7. }
  8. {
  9. "text": "Hello!"
  10. }
  11. StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
  12. {
  13. Date: Fri, 18 Apr 2014 22:29:04 GMT
  14. Server: Microsoft-HTTPAPI/2.0
  15. Content-Length: 29
  16. Content-Type: application/json; charset=utf-8
  17. }
  18. [
  19. "value1",
  20. "value2"
  21. ]
  22. StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
  23. {
  24. Date: Fri, 18 Apr 2014 22:29:04 GMT
  25. Server: Microsoft-HTTPAPI/2.0
  26. Content-Length: 10
  27. Content-Type: application/json; charset=utf-8
  28. }
  29. "id is 42"

This example is just to demonstrate that you can use the OWIN and WebApi libraries “out-of-the-box”.

For a more F# friendly web framework, have a look at Suave or WebSharper.
There is a lot more webby stuff at fsharp.org.

4. Use F# to play with UI’s interactively

The code for this section is available on github.

Another use for F# interactive is to play with UI’s while they are running — live!

Here’s an example of developing a WinForms screen interactively.

  1. open System.Windows.Forms
  2. open System.Drawing
  3. let form = new Form(Width= 400, Height = 300, Visible = true, Text = "Hello World")
  4. form.TopMost <- true
  5. form.Click.Add (fun _ ->
  6. form.Text <- sprintf "form clicked at %i" DateTime.Now.Ticks)
  7. form.Show()

Here’s the window:

Twenty six low-risk ways to use F# at work - 图3

And here’s the window after clicking, with the title bar changed:

Twenty six low-risk ways to use F# at work - 图4

Now let’s add a FlowLayoutPanel and a button.

  1. let panel = new FlowLayoutPanel()
  2. form.Controls.Add(panel)
  3. panel.Dock = DockStyle.Fill
  4. panel.WrapContents <- false
  5. let greenButton = new Button()
  6. greenButton.Text <- "Make the background color green"
  7. greenButton.Click.Add (fun _-> form.BackColor <- Color.LightGreen)
  8. panel.Controls.Add(greenButton)

Here’s the window now:

Twenty six low-risk ways to use F# at work - 图5

But the button is too small — we need to set AutoSize to be true.

  1. greenButton.AutoSize <- true

That’s better!

Twenty six low-risk ways to use F# at work - 图6

Let’s add a yellow button too:

  1. let yellowButton = new Button()
  2. yellowButton.Text <- "Make me yellow"
  3. yellowButton.AutoSize <- true
  4. yellowButton.Click.Add (fun _-> form.BackColor <- Color.Yellow)
  5. panel.Controls.Add(yellowButton)

Twenty six low-risk ways to use F# at work - 图7

But the button is cut off, so let’s change the flow direction:

  1. panel.FlowDirection <- FlowDirection.TopDown

Twenty six low-risk ways to use F# at work - 图8

But now the yellow button is not the same width as the green button, which we can fix with Dock:

  1. yellowButton.Dock <- DockStyle.Fill

Twenty six low-risk ways to use F# at work - 图9

As you can see, it is really easy to play around with layouts interactively this way.
Once you’re happy with the layout logic, you can convert the code back to C# for your real application.

This example is WinForms specific. For other UI frameworks the logic would be different, of course.


So that’s the first four suggestions. We’re not done yet!
The next post will cover using F# for development and devops scripts.