Writing F# Type Providers with the F# 3.0 Developer Preview - An Introductory Guide and Samples

Writing F# Type Providers with the F# 3.0 Developer Preview - An Introductory Guide and Samples

Rate This
  • Comments 10

A significant part of F# 3.0 support for F# Information Rich Programming is the F# Type Provider mechanism. An F# type provider is a component that provides types, properties, and methods for use in your program. For more information on F# 3.0 and the F# Type Provider mechanism, see What’s New for Visual F# in Visual Studio 11 Developer Preview.

We're very pleased to announce the availability of an introductory guide to writing F# 3.0 type providers, along with samples! The MSDN pages are here ( http://msdn.microsoft.com/en-us/library/hh361034(v=vs.110).aspx) . The samples and support code are part of the F# 3.0 Samples Pack on codeplex.The samples include 

  • The HelloWorldTypeProvider which shows how to some simple provide types, properties and methods
  • The RegexTypeProvider which shows how to give typesafe and statically checked access to regular expressions
  • The MiniCsvTypeProvider which gives typesafe access to CSV files based on a schema given on the first line of the file.

To use this guide you will need to install the Visual Studio 11 Developer Beta. This is preliminary documentation and should not be considered a definitive or final guide to writing type providers.

To give you a taste, the code below shows writing a provider which provides one type with one static member.

open Samples.FSharpPreviewRelease2011.ProvidedTypes

open Microsoft.FSharp.Core.CompilerServices

[<TypeProvider>]

type SampleTypeProvider(config: TypeProviderConfig) as this =

   inherit TypeProviderForNamespaces()

   let namespaceName = "Samples.HelloWorldTypeProvider"

   let thisAssembly = Assembly.GetExecutingAssembly()

   let theType =

       ProvidedTypeDefinition(thisAssembly,namespaceName,

                              typeName = "Type" + string n,

                              baseType = Some typeof<obj>,

                              IsErased = true)

   let staticProp =

       ProvidedProperty(propertyName = "StaticProperty",

                        propertyType = typeof<string>,

                        IsStatic=true,

                        GetterCode= (fun args -> <@@ "Hello!" @@>))

   do theType.AddMember staticProp

   do this.AddNamespace(namespaceName, [ theType ]

[<assembly:TypeProviderAssembly>]

do()

Please send us your feedback! You may submit feedback by emailing fsbugs@microsoft.com. Please note that this document is not designed to be a specification of the F# 3.0 type provider mechanism, which we will be publishing separately (though not as part of the Developer Preview). Some information is available on the MSDN pages.

Don Syme, Keith Battocchi and the Visual Studio F# Team

 

Leave a Comment
  • Please add 3 and 4 and type the answer here:
  • Post
  • The link to "F# 3.0 Samples Pack" got an additional . (dot) after com :)

  • I asked this on the previous blog post and did not get an answer. How does an F# Type Provider differ from any other type which is designed to represent a specific schema?

  • Hi David,

    A type provider *supplies* types.  These types can be normal .NET types (as created by a code generator, for instance; these are called "generated types") or they can be simulated (these are called "erased" types, since uses of these types end up being rewritten in terms of existing types).  Among other scenarios, erased types are helpful when there is a prohibitively large or even potentially unbounded set of logical types.

    In the case of the type providers which come out of the box in the developer preview, the provided types are similar to what you would get with a code generator for typed access to an external data source, but there is no separate code generation step - when you write the code to use the type provider, you include the information about the data source that you want to connect to (e.g. the URL for an OData service) and the compiler gives you strongly-typed access to the data source.  For example, in Don's last post he shows how you can access the Netflix catalog via OData, exposing collections like Titles and People with the properties you'd expect, such as Name, etc.  This works really well with F#'s interactive style of development.

    Looking at some of the examples, either in the document attached to this blog post or on MSDN may help to explain some of the many uses for type providers.  Please let us know if you have any other questions.

    Regards,

    Keith

  • Just a small typo, the first link refers to the it-it page, it should be en-US. Other than that, great post.

  • @Keith,

    Thanks for the explanation. So the idea is to "dynamically" provide static types at compile-time?

    My first thought after looking at the RegexTypeProvider and the MiniCsvTypeProvider was "why wouldn't you just do this with T4?" Then I remembered that T4 doesn't work in F#. Is there a particular reason why these use cases weren't addressed by extending T4 support to F# (which seems to be a common ask)? It seems like that would have been a more platform-consistent mechanism for achieving essentially the same result. For that matter, why doesn't T4 work for F# already? It is just a text generation engine, and it was designed (as far as I can tell) to be essentially language-agnostic. So why do we have to resort to these kinds of workarounds?

    Disclosure: I am only a casual F# user; C# is my primary language.

  • Please ship more ready to use type provider in F# 3.0, like a generic csvProvider that can read any simple type data for each column, and can specify whether to skip header lines etc, not just float data as in the minicsvprovider example.

    If one has always to write his own provider, this solution is not much appealing...

  • @David

    Although it might be possible to achieve similar results with T4 in some cases, for others it would be impossible.  For instance, one of the examples that Don often uses at talks is a Freebase type provider, which has thousands of logical types.  It would be impractical and wasteful to generate all of these types when any given application might only need a few of them.  Instead, the Freebase type provider uses erased types to give the user a strongly typed interface to Freebase which lazily instantiates logical types without actually generating any additional real types.  Furthermore, I think that the model for interacting with type providers works much better with tools like F# interactive than a standard code-generation approach would.

    I can't speak to why T4 doesn't work with F#.

    Regards,

    Keith

  • I am just trying to understand the reasoning that lead to the design and implementation of this feature. It seems to me that making T4 work directly in F# - which definitely needs to be done, and should be straightforward, since again it is just a text generation engine, and has in fact been shown to work in F# with some ugly workarounds - would have addressed most of the scenarios that the Type Providers feature seems to be targeting, using a mechanism that was already built and in use across the rest of the .NET platform. Plus T4 seems to be much more flexible than type providers.

    The only scenarios that I can see where Type Providers might have some benefit over T4 are when targeting massive logical schemas such as Freebase, where using erased types saves on some assembly bloat. But that seems like a pretty narrow use case with a pretty marginal benefit for what had to be an expensive feature to implement.

    I'm not trying to be negative; from a technical perspective it is certainly a very interesting feature. But the language designer in me feels the need to play devil's advocate.

  • Unmatched ( in line:

    do this.AddNamespace(namespaceName, [ theType ]

  • Has anyone found a way to log the SQL queries out of a Entity Framework SQL type provider? I see LINQ-to-SQL providers have access to the query right off the context object. I tried casting the F# query (QueryBuilder) to an ObjectQuery without success...

Page 1 of 1 (10 items)