Type Providers, Record / Union Types and Constant Type unsupported

When writing type providers you are required to define code that will run at run-time with a quotation. This in itself is not a problem, however if you try and pass a none native type to the quotation you will receive the following error,

Unsupported constant type: xxxx

There is a stack-overflow post here which has an example and a good explanation of the reasons why. A typical work around is to use each field from a record and pass it to a function call in the quotation as an array or as individual parameters. Either way this can end up being quite painful.

So how can we work around this. Well, what we need to do is build a new instance of the object we are trying to pass to the quotation within the quotation itself, and then use the variable that holds this new instance as the parameter in the function call in the Quotation. I have probably not explained that the best but the final code looks like this.

            ProvidedMethod(sproc.Name.ProcName,
                           parameters,returnType, 
                           InvokeCode = QuotationHelpers.quoteRecord recordInstance (fun args var ->  <@@ ((%%args.[0] : MyType)).SomeMethod(%%var)) @@>))
            

Where the args are the original arguments passed by provided method invoke code and var is a quotation that represents our record instance to pass to our method. The implementation of QuotationHelpers is as follows.

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Reflection

module QuotationHelpers = 

    let rec coerceValues fieldTypeLookup fields = 
        Array.mapi (fun i v ->
                let expr = 
                    if v = null then simpleTypeExpr v
                    elif FSharpType.IsUnion (v.GetType()) then unionExpr v |> snd
                    elif FSharpType.IsRecord (v.GetType()) then recordExpr v |> snd
                    else simpleTypeExpr v
                Expr.Coerce(expr, fieldTypeLookup i)
        ) fields |> List.ofArray
    
    and simpleTypeExpr instance = Expr.Value(instance)

    and unionExpr instance = 
        let caseInfo, fields = FSharpValue.GetUnionFields(instance, instance.GetType())    
        let fieldInfo = caseInfo.GetFields()
        let fieldTypeLookup indx = fieldInfo.[indx].PropertyType
        caseInfo.DeclaringType, Expr.NewUnionCase(caseInfo, coerceValues fieldTypeLookup fields)

    and recordExpr instance = 
        let tpy = instance.GetType()
        let fields = FSharpValue.GetRecordFields(instance)
        let fieldInfo = FSharpType.GetRecordFields(tpy)
        let fieldTypeLookup indx = fieldInfo.[indx].PropertyType
        tpy, Expr.NewRecord(instance.GetType(), coerceValues fieldTypeLookup fields)

    and arrayExpr (instance : 'a array) =
        let typ = typeof<'a>
        let arrayType = instance.GetType()
        let exprs = coerceValues (fun _ -> typ) (instance |> Array.map box)
        arrayType, Expr.NewArray(typ, exprs)

    let createLetExpr varType instance body args = 
        let var = Var("instance", varType)  
        Expr.Let(var, instance, body args (Expr.Var(var)))

    let quoteUnion instance = unionExpr instance ||> createLetExpr
    let quoteRecord instance = recordExpr instance ||> createLetExpr
    let quoteArray instance = arrayExpr instance ||> createLetExpr

And thats it. Hopefully this should remove some pain points in developing type providers.

Posted in Development | Tagged , | 2 Comments

Introducing Java type provider

A while ago I blogged about some development I was working on with IKVM and type providers. At the time the type provider only worked with primitive types. Recently I have had time to take this a bit further and with the help of the F# team this type provider is now finally useful :).

iText Example

iText is a PDF generation library available from here.

import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;

public class HelloWorld {

    public static final String RESULT
        = "results/part1/chapter01/hello.pdf";

    public static void main(String[] args)
    	throws DocumentException, IOException {
    	new HelloWorld().createPdf(RESULT);
    }

    public void createPdf(String filename)
	throws DocumentException, IOException {
        Document document = new Document();
        PdfWriter.getInstance(document, new FileOutputStream(filename));
        document.open();
        document.add(new Paragraph("Hello World!"));
        document.close();
    }
}

Once you have downloaded the iText JAR and IKVM (available from here), unzip them and place them into your project directory. Once you have done this you are ready to use the JavaTypeProvider.

module PDF =
    let[<Literal>] private jar = @"D:\Appdev\IKVM.TypeProvider\JavaSource\itext\itextpdf-5.4.4.jar"
    let[<Literal>] private ikvmPath = @"D:\Appdev\IKVM.TypeProvider\IKVM\bin\"

    type private Jar = Java.JavaProvider<JarFile=jar, IKVMPath=ikvmPath>
    type private iText = Jar.com.itextpdf.text
    type private PDF = Jar.com.itextpdf.text.pdf

    let createPDF (filename:string) (contents:string) =
        let document = new iText.Document();
        PDF.PdfWriter.getInstance(document, new java.io.FileOutputStream(filename)) |> ignore
        document.``open``()
        document.add(new iText.Paragraph(contents)) |> ignore
        document.close();

module Program =

    [<EntryPoint>]
    let main argv =
        let fname = "D:\mypdf.pdf"
        PDF.createPDF fname "Hello, from java"
        printfn "PDF written to %s" fname
        System.Console.ReadLine() |> ignore
        0 // return an integer exit code

For the code above you can see that we can open namespaces in the JAR by creating type aliases. Notice that the use of the java.io.FileOutputStream type. Some types that the IKVM compiler generates are part of the IKVM.OpenJDK set of libraries. You will need to reference the appropriate libraries to use these generated types. In the case of iText you will need to and references to IKVM.OpenJDK.Core and IKVM.AWT.Swing.

The type provider is available on nuget, grab it by

  >Install-Package JavaTypeProvider

More samples and the type provider implementation can be found in the GitHub Repository this is still early days and I would be interested in seeing what this works with and what it doesn’t.

Posted in Development | Tagged , , | 4 Comments

F# Actor: An Actor Library

Wikipedia, defines an actor as -

An actor is a computational entity that, in response to a message it receives, can concurrently:

  • send a finite number of messages to other actors;
  • create a finite number of new actors;
  • designate the behavior to be used for the next message it receives.

Recently there has been some discussion in the F# open source community about an Akka like actor framework for F#. The following post introduces a very early version of the framework, in the hope that it will get some community interest and contributions.

Creating actors and sending messages

To create an actor we need to simply provide a name and a function that takes an actor instance and returns a unit Async computation

let multiplication = 
    (fun (actor:Actor<_>)  ->
        async {
            let! (a,b) = actor.Receive()
            let result = a * b
            do printfn "%A: %d * %d = %d" actor.Path a b result
        }
    )

let addition = 
    (fun (actor:Actor<_>) ->
        async {
            let! (a,b) = actor.Receive()
            let result = a + b
            do printfn "%A: %d + %d = %d" actor.Path a b result
        }
    )

let calculator = 
    [
       Actor.spawn (ActorPath.create "calculator/addition") addition
       Actor.spawn (ActorPath.create "calculator/multiplication") multiplication
    ]

Here we have created two actors, one that carries out multiplication and one that carries out addition. To send a message to the actors we can simply get the instance and call the post method.

calculator.[0].Post((5,2))

However in an actor framework having to directly reference the actors to call post on them can be some what limiting. So when each actor is created it is assigned a path. The path is created with the following schema (actor://{machinename}/{path}). We can use this path to resolve the actor,

"actor://main-pc/calculator/addition" ?<-- (5,2)

If we know that this actor is local then we do not need to qualify the path.

"calculator/addition" ?<-- (5,2)

In addition to resolving single actors we can also broad cast to several actors at once by providing a partial path,

"calculator/" ?<-- (5,2)

Sending Messages to Remote Actors

Messages are sent via transports. Out of the box, the framework provides a TCP transport based on the high performance Fracture I/O library. Before you can send remote messages you must register a transport.

let transport = new FractureTransport({ Port = Some 8080}) :> ITransport
Remoting.registerTransport Serialisers.Binary transport

When a transport is created it is wrapped in a actor of Actor and path ‘transports/{scheme}’ in the case of the fracture transport this would be ‘transports/actor.fracture’. This actor is then supervised (see below) by the system/remotingsupervisor actor, which is initialised the a OneForOne strategy so will restart the transport if it errors at any point. Once a transport is registered we can then send a message to a remote actor by using a fully qualified actor path, for example,

"actor.fracture://10.256.76.94:8080/calculator/addition" ?<-- (5,2)

notice here that the scheme selects which transport the message will be sent on. If you wanted to send a message on another registered transport (http for example), the path would be,

"actor.http://10.256.76.94:8082/calculator/addition" ?<-- (5,2)

Supervisors

Supervisors, provide a way to monitor make decisions about what to do when a actor errors. How the supervisor responds when an actor receives an error depends on the strategy provided (for more info see here.

To create a supervised actor, we can simply do the follwoing

let err = 
    (fun (actor:Actor<string>) ->
        async {
            let! msg = actor.Receive()
            if msg <> "fail"
            then printfn "%s" msg
            else failwithf "ERRRROROROR"
        }
    ) |> Actor.spawn (ActorPath.create "err_0")

let supervisor =  Actor.supervisor (ActorPath.create "oneforone") Supervisor.OneForOne [err]

if we now post ‘fail’ to this actor it will throw an exception and the supervisor will step in and restart the actor.

Conclusion

This has just been a brief introduction into the framework, there is much more in the pipeline the project is in its very early stages. I welcome anyone who wants to contribute and shape this into a fully fledged actor framework. So basically rip it apart tell let me know what you like don’t like, send pull requests raise bugs, feature requests, improve documentation. Any contribution will be welcomed.

The source for this can be found on GitHub here. And more complete documentation here

Posted in Development | Tagged , | 3 Comments

F# 3 and Raven DB

Ok so I have blogged about these to before. Previously, F# didn’t have brilliant support for Linq. F# Expressions couldn’t `easily` be converted to the Linq expression trees that the RavenDB API required. This caused somewhat of a mis-match between the two which made Raven difficult but not impossible to use from F#. My previous blog introduced a library which is available for Raven clients prior to version 2.0, to bridge this gap, and tried to make Raven more natural to use from F#. However as of Raven 2.0 this library has been removed. The reasons are explained here. I don’t disagree with the reasons ayende cut the support
I wouldn’t want to support something I had little knowledge of either. However things have changed…. :)

The advent F# 3 and query expressions

So we are now in the era of F# 3.0 and things have changed somewhat. F# is now truly in the data era… Information Rich programming is an awesome feature of F# manifested in the
form of `Type Providers` and `Query Expressions`. If you haven’t read about or don’t know what type providers are then I encourage you to check them out here. Type providers are not really applicable for use with RavenDB see it is schemaless so for the rest of thispost we will focus on `Query Expressions`. It is this feature that means the gap between Linq and F# no longer exists. If you are familiar with

var result = (from x in xs do
	      where x.Published >= someDate
	      select x.Name).ToArray()

then the query expression syntax shouldn’t feel that different,

let result =
     query {
            for x in xs do
	        where (x.Published >= someDate)
	        select x.Name
	   } |> Seq.toArray

So What about RavenDB???

Using RavenDB from C# is well documented and things are not that different when using it from F#. The in’s and out’s are well known and lets face it the API is your safety net. It doesn’t let you kill yourself, in fact you have to try very hard to actually do anything really bad in RavenDB. This is I think the best feature of RavenDB.

So, what are the things that we need to be aware of when using RavenDB from F#? First things first, initializing the document store. This can be done pretty much the same as in C#

let store = new DocumentStore(Url = "http://localhost:8080")

and this is all well and good if we just use straight forward POCO objects. But what if we want to use F# record or Union types? We need to make a few simple changes.
Lets first consider F# record types, all we need to do here is declare the `Id` property as mutable.

type BlogPost = {
	mutable Id : string
	Body : string
	....//other members
}

Simple eh?, but what about Union types, Maps, F# lists? These are a little more complex as Json.NET doesn’t do the correct thing to serialize these out of the box. However Json.NET and the
internalised Raven counterpart does have an extension point and a UnionTypeConverter or MapTypeConverter as Json.NET implementations can be found here. To use this we need to modify our
document store setup a little to include the converter.

let store =
        let customiseSerialiser (s : JsonSerializer) =
            s.Converters.Add(new MapTypeConverter())
            s.Converters.Add(new UnionTypeConverter())

        let store = new DocumentStore(Url="http://localhost:8080")
        store.Conventions.CustomizeJsonSerializer <- (fun s -> (customiseSerialiser s))
        store.Initialize()

Querying raven

With the document store setup we can now start querying Raven. As with any Raven query we need to create a session from our document store, then we need to create the query.

let getPostsAsOf store asOfDate = 
    use session = store.OpenSession()
    query {
	for post in session.Query() do
	where (post.Published >= asOfDate)
	select post
    }

The above creates a query that is pending execution. To execute this we can run,

let posts = 
    getPostsAsOf store (DateTime.Now.AddDays(-2.).Date) 
    |> Seq.toArray

this will give us an array of BlogPosts published from 2 days ago. Notice we had to enumerate to an array for the query to actually be executed. This is the same execution semantics
as C#; and it is important to realise that there isn’t really any magic going on in the world of F#, it is still just a .NET lanuguage it still compiles to CIL and is fully
interoperable with any other .NET library.

Indexes

OK so things haven’t got much better here in terms of static indexes. Basically you still need to define them in C# and then you can extend the document initialization process by
including the assembly that contains the index definitions. However in Raven 2.0, dynamic indexes and promotion to permanent indexes have been massively improved, which reduces the need to create static indexes.

Posted in Development | Tagged , | 2 Comments

Option Operators

We often have to represent the absence of data within a collection of values. In C# the default type to-go to is an Nullable, F# 3.0 introduced the Microsoft.FSharp.Linq.NullableOperators module to help with comparisons and arithmetic over this type.

The Nullable type can still be somewhat tiresome to use in F# though as it can lead to adding lots of type constraints for example

type NullableSeq<'a when 'a : (new : unit ->'a) 
                    and 'a : struct 
                    and 'a :> ValueType> = seq<Nullable<'a>>

I think a nicer approach is to replace Nullable with Option, to relax some of these type constraints.

type OptionSeq<'a> = seq<Option<'a>>

however in doing this we have lost the nice operators. But this is fairly easy to recreate as the semantics of Nullable and Option are approximately the same. So with a quick copy of the NullableOperators module and some simple find and replace we have the exact same set of operators.

module OptionOperators

    open System
    let (?>=) (x : Option<'T>) (y: 'T) = x.IsSome && x.Value >= y

    let (?>) (x : Option<'T>) (y: 'T) = x.IsSome && x.Value > y

    let (?<=) (x : Option<'T>) (y: 'T) = x.IsSome && x.Value <= y

    let (?<) (x : Option<'T>) (y: 'T) = x.IsSome && x.Value < y

    let (?=) (x : Option<'T>) (y: 'T) = x.IsSome && x.Value = y

    let (?<>) (x : Option<'T>) (y: 'T) = not (x ?= y)

    let (>=?) (x : 'T) (y: Option<'T>) = y.IsSome && x >= y.Value

    let (>?) (x : 'T) (y: Option<'T>) = y.IsSome && x > y.Value

    let (<=?) (x : 'T) (y: Option<'T>) = y.IsSome && x <= y.Value

    let (<!--?) (x : 'T) (y: Option<'T-->) = y.IsSome && x < y.Value

    let (=?) (x : 'T) (y: Option<'T>) = y.IsSome && x = y.Value

    let (<>?) (x : 'T) (y: Option<'T>) = not (x =? y)

    let (?>=?) (x : Option<'T>) (y: Option<'T>) = (x.IsSome && y.IsSome && x.Value >= y.Value)

    let (?>?) (x : Option<'T>) (y: Option<'T>) = (x.IsSome && y.IsSome && x.Value > y.Value)

    let (?<=?) (x : Option<'T>) (y: Option<'T>) = (x.IsSome && y.IsSome && x.Value <= y.Value)

    let (?<!--?) (x : Option<'T-->) (y: Option<'T>) = (x.IsSome && y.IsSome && x.Value < y.Value)

    let (?=?) (x : Option<'T>) (y: Option<'T>) = (not x.IsSome && not y.IsSome) || (x.IsSome && y.IsSome && x.Value = y.Value)

    let (?<>?) (x : Option<'T>) (y: Option<'T>) = not (x ?=? y)

    let inline (?+) (x : Option<_>) y = if x.IsSome then Some(x.Value + y) else None
    let inline (+?) x (y: Option<_>) = if y.IsSome then Some(x + y.Value) else None
    let inline (?+?) (x : Option<_>) (y: Option<_>) = if x.IsSome && y.IsSome then Some(x.Value + y.Value) else None

    let inline (?-) (x : Option<_>) y = if x.IsSome then Some(x.Value - y) else None
    let inline (-?) x (y: Option<_>) = if y.IsSome then Some(x - y.Value) else None
    let inline (?-?) (x : Option<_>) (y: Option<_>) = if x.IsSome && y.IsSome then Some(x.Value - y.Value) else None

    let inline ( ?*  ) (x : Option<_>) y = if x.IsSome then Some(x.Value * y) else None
    let inline ( *?  ) x (y: Option<_>) = if y.IsSome then Some(x * y.Value) else None
    let inline ( ?*? ) (x : Option<_>) (y: Option<_>) = if x.IsSome && y.IsSome then Some(x.Value * y.Value) else None

    let inline ( ?%  ) (x : Option<_>) y = if x.IsSome then Some(x.Value % y) else None
    let inline ( %?  ) x (y: Option<_>) = if y.IsSome then Some(x % y.Value) else None
    let inline ( ?%? ) (x : Option<_>) (y: Option<_>) = if x.IsSome && y.IsSome then Some(x.Value % y.Value) else None

    let inline ( ?/  ) (x : Option<_>) y = if x.IsSome then Some(x.Value / y) else None
    let inline ( /?  ) x (y: Option<_>) = if y.IsSome then Some(x / y.Value) else None
    let inline ( ?/? ) (x : Option<_>) (y: Option<_>) = if x.IsSome && y.IsSome then Some(x.Value / y.Value) else None
Posted in Development, Uncategorized | Tagged , | 2 Comments

F# IKVM Type Provider

After reading Sergey Tihon’s post about IKVM and the stanford parser. I thought I’d try and create a IKVM type provider.

The first version can be found on my GitHub account here.
The following code shows a simple sample on how to use the type provider.

    let\[<Literal>\] jar = @"D:\Appdev\IKVM.TypeProvider\IKVM.TypeProvider.Tests\SimpleJar\out\artifacts\SimpleJar.jar"
    let\[<Literal>\] ikvmPath = @"D:\Appdev\IKVM.TypeProvider\IKVM\bin\"

    type Jar = IKVM.IKVMProvider<JarFile=jar, IKVMPath=ikvmPath>
    type HW = Jar.hello.HelloWorld

    \[<EntryPoint>\] 
    let main(args) =
        let hw = new HW("IKVM")
        printf "%s" (hw.Say("Hello from java, well .NET"))
        printf "%s" (hw.Close())
        System.Console.ReadLine() |> ignore
        0

The above is the same sample included in the source. As you can see it requires an IKVM distribution your machine and requires your consuming project to reference IKVM.OpenJDK.Core.

This is very early days, for this so I would be surprised if it works for anything even moderately complex. But I hope to change this to support everything that IKVM supports assuming I get the time, in my day job :). Feel free to have a play and let me know what works and what doesn’t.

The biggest gripe I have at the minute is that the type providers don’t allow direct references to generated types, hence HW representing the class I wish to use. I would prefer to just open the “namespace“ as a type and then use the classes from there. Like the following

    let\[<Literal>\] jar = @"D:\Appdev\IKVM.TypeProvider\IKVM.TypeProvider.Tests\SimpleJar\out\artifacts\SimpleJar.jar"
    let\[<Literal>\] ikvmPath = @"D:\Appdev\IKVM.TypeProvider\IKVM\bin\"

    type Jar = IKVM.IKVMProvider<JarFile=jar, IKVMPath=ikvmPath>
    type helloNS = Jar.hello

    \[<EntryPoint>\] 
    let main(args) =
        let hw = new helloNS.HelloWorld("IKVM")
        printf "%s" (hw.Say("Hello from java, well .NET"))
        printf "%s" (hw.Close())
        System.Console.ReadLine() |> ignore
        0

I suspect not being able to do this will become problematic for large assemblies. as you will have to create an indirect reference for each type that you used.

Posted in Uncategorized | Tagged , , | 3 Comments

F# end to end

Introduction

Recently my colleague @simontcousins published an article comparing to similar projects one written in C# one written in F#. The conclusion is that for the two projects the F# one is about 4% of the size.  You can read more about this here.

Now normally, a typical project comprises of several languages / technologies.

  • Application Code -> C#
  • Build -> MSBuild/Nant
  • Deploy -> Powershell script/Batch script
  • UI (Web) -> HTML/Javascript
  • Documentation -> Word/HTML

However the F# project in question here has a profile more like this,

  • Application Code -> F#
  • Build -> F#
  • Deploy -> F#
  • UI (Web) -> HTML/CSS/Javascript
  • Documentation -> F#

Note the stack is ‘almost’ completely F# (we actually could have made this completely F# see below). Maybe I’m biased but I think that this is a huge benefit for maintainability I only need to have my F# brain switched on and I can change any part of the application. Sure I have to learn a few libraries, but the playfulness offered by the REPL here makes testing and experimenting easy; this is especially true when it comes writing build and deployment scripts, which I normally find quiet difficult to test.

Full stack F#

So is it possible to use F# for everything Build, Deployment, UI (Web/WPF), Documentation. The answer is simply YES!! There is just a few libraries we need to know about to achieve this. Lets look at each area of a typical application and see which libraries we can use.

Application Logic

Ok this might seem like an obvious one, just write F#, but I thought I’d use this as an opportunity to highlight some libraries that I find useful

  • FSharpx – Contains lots of extensions to the F# core modules, many useful data structures, commonly used monads, validation, type providers, async extensions etc.
  • FSharp.Data – Contains implementation of various type providers such as CSV, XML and JSON and I’m sure as the library matures we will see a lot more implementations to connect to wide variety of data sources.
  • FSharpEnt- Contains more enterprise based helpers for F#. This will soon be replaced by a newer version which reduces the overlap with FSharpx, the (very early) version can be found here, I just need to find some time to do this :).

Build and Deployment

To build and deploy application with F# we can use FAKE. FAKE allows you to write your build and deployment scripts in F#. A simple script might look something like this

// include Fake libs
#I @"..\..\tools\FAKE";
#r "FakeLib.dll";
open Fake

// *** Define Targets ***

Description "Cleans the last build"
Target "Clean" (fun () ->
    trace " --- Cleaning stuff --- "
)

Target "Build" (fun () ->
    trace " --- Building the app --- "
)

Target "Deploy" (fun () ->
    trace " --- Deploying app --- "
)

// *** Define Dependencies ***
"Clean"
  ==> "Build"
  ==> "Deploy"

// *** Start Build ***
RunParameterTargetOrDefault "target" "Deploy"

The really nice thing about this is you have the full .NET framework and the full power of F# available in your scripts. Additionally FAKE also has an accompanying website, which allows you to manage your deployment agents, so you can easily deploy, upgrade or rollback applications from a central place. As of writing this is in its early stages but the latest source for this feature can be found on my fork.

UI

How you tackle writing a UI in F# obviously depends on your choice of technologies. There are others obviously but the two I’m going to consider are WPF and HTML/CSS/Javascript.

WPF

If you choose to write your UI using WPF then things are fairly straight forward, Write XAML markup and then use code behind F#. However wiring up the code behind can be a pain because of the C# code gen involved, typically you have to load the view yourself using a XAML reader, or code the view layout in F# as in these series of examples from John Laio. If however you want to keep XAML markup then FSharpx has a XAML type provider that helps things along here.

open System
open System.Windows
open System.Windows.Controls
open FSharpx

type MainWindow = XAML<"Window.xaml">;

let loadWindow() =
    let window = MainWindow()
    window.Button1.Click.Add(fun _ ->;
        MessageBox.Show("Hello world!")
        |> ignore)
    window.Root

[<STAThread>]
(new Application()).Run(loadWindow())
|> ignore

See Steffan Forkmanm’s post for more information about this. Lets also not forget about first class events and the asynchronous programming model in F# that makes writing responsive UI’s that much easier.

HTML/CSS/Javascript

If you go webby then things get a little more interesting, we have several options available here.

  • WebSharper – This is a very complete web framework, I have not personally played with it yet but I understand it does everything you’d want and more. Well worth checking out.
  • FunScript – A new project, but it exploits the power of type providers to offer strongly typed access to TypeScript files @thomaspetricek has a nice talk about it here. With fun script you still have to write the HTML markup, although providing a Combinator library to emit the markup wouldn’t be that difficult. (If some one knows of one I’ll add it here), but this isn’t application logic anyway. The important stuff is still written in F# and compiled to javascript later on.

Documentation

@thomaspetricek recently released FSharp.Formatting we can generate documentation from an F# script file, using a mix of markdown and F#, for an example see this link. This can then be integrated into your FAKE build script, using a build target something like this.

Target "Docs" (fun _ ->; 
    let template = Path.Combine(currentDirectory, "template.html")
    let sources = Path.Combine(__SOURCE_DIRECTORY__, "samples")
    let output = docsDir
    
    Literate.ProcessDirectory(sources, template, output)

    XCopy docsDir "docs";
)

Conclusion

Ok I might of over stated that everything can be written in F#, certainly at the moment there is a lack of libraries for emitting XAML and HTML (with the exception of WebSharper of course). But HTML and XAML are really inconsequential when it comes the to the correctness of your application they do not contain any logic which needs to be tested they simply control layout. The important thing to take from the above is the fact that all of your logic whether it is for build, deployment, UI interaction, example documentation can be written in a type safe way using the various libraries and F# feature spoken about above.

Posted in Development | Tagged , | 17 Comments