Welcome! I am Loïc Denuzière aka "Tarmil", and this is my technical blog. I'm a French developer who's quite passionate about functional programming, and I've been using F# for most of my work for over ten years.

I've been one of the main developers of WebSharper, the F# web framework with both server-side and JavaScript-compiled client-side tools. Recently I've been focusing more on Bolero, a library that runs F# applications in WebAssembly using Blazor, and other personal projects.

Follow me on Twitter, Mastodon and find me on GitHub.

FSharp.Data.LiteralProviders 1.0 is here!

I am happy to announce that the library FSharp.Data.LiteralProviders has reached version 1.0!

FSharp.Data.LiteralProviders is an F# type provider library that provides compile-time constants from various sources, such as environment variables or files:

open FSharp.Data.LiteralProviders

// Get a value from an environment variable, another one from a file,
// and pass them to another type provider.

let [<Literal>] ConnectionString = Env<"CONNECTION_STRING">.Value
let [<Literal>] GetUserDataQuery = TextFile<"GetUserData.sql">.Text

type GetUserData = FSharp.Data.SqlCommandProvider<GetUserDataQuery, ConnectionString>

let getUserData (userId: System.Guid) =
    GetUserData.Create().Execute(UserId = userId)

Here is a summary of the new features in v1.0.

Running an external command

The Exec provider runs an external command during compilation and provides its output.

open FSharp.Data.LiteralProviders

let [<Literal>] Branch = Exec<"git", "branch --show-current">.Output

More options are available to pass input, get the error output, the exit code, etc. See the documentation.

Conditionals

The sub-namespaces String, Int and Bool provide a collection of compile-time conditional operators for the corresponding types.

For example, you can compare two integer values with Int.LT; combine two booleans with Bool.OR; or choose between two strings with String.IF.

open FSharp.Data.LiteralProviders

// Compute the version: get the latest git tag, and add the branch if it's not master or main.

let [<Literal>] TagVersion = Exec<"git", "describe --tags">.Output

let [<Literal>] Branch = Exec<"git", "branch --show-current">.Output

// Note: the `const` keyword is an F# language quirk, necessary when nesting type providers.
let [<Literal>] IsMainBranch =
    Bool.OR<
        const(String.EQ<Branch, "master">.Value),
        const(String.EQ<Branch, "main">.Value)
    >.Value

let [<Literal>] Version =
    String.IF<IsMainBranch,
        Then = TagVersion,
        Else = const(TagVersion + "-" + Branch)
    >.Value

See the documentation for all the operators available.

Value as int and as bool

The providers try to parse string values as integer and as boolean. If any of these succeed, a value suffixed with AsInt or AsBool is provided.

open FSharp.Data.LiteralProviders

let [<Literal>] runNumberAsString = Env<"GITHUB_RUN_NUMBER">.Value // eg. "42"

let [<Literal>] runNumberAsInt = Env<"GITHUB_RUN_NUMBER">.ValueAsInt // eg. 42

By Loïc "Tarmil" Denuzière on Friday, May 27, 2022

fsharp release library literalproviders Tweet Permalink