One of the many things in FSharpx that I find useful is the TypeProviderDSL. This is a DSL that sits on top of the ProvidedTypes module provided in the F# 3.0 Sample Pack. With this DSL and a few other helpers in FSharpx, the code from the AppSettings Type Provider that I showed in a previous post becomes easier to read. Plus, a few lines of code are shaved off in the process.
Let's look at a few of the features of the TypeProviderDSL that are used by the AppSettings Type Provider.
1. The erasedType function provides a simple way to create a ProvidedTypeDefinition.
2. The staticParameter function encapsulates the code needed to define a static parameter.
3. The literalField function makes it slightly easier to create a ProvidedLiteralField.
4. The addXmlDoc function provides a common way to add XML documentation.
5. Lastly, the |+> operator makes it very easy to add members.
Here's the end result:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module SampleTypeProviderWithFSharxDSL | |
open FSharpx.TypeProviders.DSL | |
open Microsoft.FSharp.Core.CompilerServices | |
open Samples.FSharpPreviewRelease2011.ProvidedTypes | |
open System | |
open System.Configuration | |
open System.IO | |
open System.Reflection | |
let rootNamespace = "SampleTypeProviderWithFSharxDSL" | |
let thisAssembly = Assembly.GetExecutingAssembly() | |
let tryParseWith func = func >> function | |
| true, value -> Some value | |
| false, _ -> None | |
let (|Bool|_|) = tryParseWith Boolean.TryParse | |
let (|Int|_|) = tryParseWith Int32.TryParse | |
let (|Double|_|) = tryParseWith Double.TryParse | |
let addTypedAppSettings (cfg:TypeProviderConfig) (configFileName:string) (tyDef:ProvidedTypeDefinition) = | |
try | |
let filePath = Path.Combine(cfg.ResolutionFolder, configFileName) | |
let fileMap = ExeConfigurationFileMap(ExeConfigFilename=filePath) | |
let appSettings = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None).AppSettings.Settings | |
Seq.iter (fun (key) -> | |
tyDef | |
|+> match (appSettings.Item key).Value with | |
| Int fieldValue -> literalField key fieldValue | |
| Bool fieldValue -> literalField key fieldValue | |
| Double fieldValue -> literalField key fieldValue | |
| fieldValue -> literalField key fieldValue | |
|> addXmlDoc (sprintf "Returns the value from the appSetting with key %s" key) | |
|> ignore) appSettings.AllKeys | |
tyDef | |
with | |
| exn -> tyDef | |
let typedAppSettings (cfg:TypeProviderConfig) = | |
erasedType<obj> thisAssembly rootNamespace "AppSettings" | |
|> staticParameter "configFileName" (fun typeName configFileName -> | |
erasedType<obj> thisAssembly rootNamespace typeName | |
|> addTypedAppSettings cfg configFileName ) | |
[<TypeProvider>] | |
type public SampleAppSettingProvider(cfg:TypeProviderConfig) as this = | |
inherit TypeProviderForNamespaces() | |
do this.AddNamespace(rootNamespace, [typedAppSettings cfg]) | |
[<TypeProviderAssembly>] | |
do () |
You can get FSharpx.TypeProviders from the NuGet Gallery at http://www.nuget.org/List/Packages/FSharpx.TypeProviders and find the source on GitHub at https://github.com/fsharp/fsharpx/tree/TypeProviders.