Generics in F#

Starting with version 5.0, F# has added support for generics, which are similar to type parameters in other languages.

As an example of a generic function, slicesIndex takes a list of any type that supports equality comparison and an element of that type, and returns the index of the first occurrence of v in s, or -1 if not present.

let slicesIndex<'T when 'T : equality> (s: 'T list) (v: 'T) =
    match List.tryFindIndex (fun x -> x = v) s with
    | Some i -> i
    | None -> -1

As an example of a generic type, List<'T> is a built-in F# type that represents a singly-linked list with values of any type.

We can define functions that operate on generic types. Here’s an example of a function that pushes an element to the end of a list:

let push<'T> (lst: 'T list) (v: 'T) =
    lst @ [v]

Here’s a function that returns all elements of a list:

let allElements<'T> (lst: 'T list) =
    lst

Now let’s use these generic functions and types:

let main() =
    let s = ["foo"; "bar"; "zoo"]

    // When invoking generic functions, we can often rely
    // on type inference. Note that we don't have to
    // specify the type for 'T when calling slicesIndex
    // - the compiler infers it automatically.
    printfn "index of zoo: %d" (slicesIndex s "zoo")

    // We could also specify the type explicitly if needed
    let _ = slicesIndex<string> s "zoo"

    let mutable lst = []
    lst <- push lst 10
    lst <- push lst 13
    lst <- push lst 23
    printfn "list: %A" (allElements lst)

main()

To run the program, save it as generics.fsx and use the F# interpreter:

$ dotnet fsi generics.fsx
index of zoo: 2
list: [10; 13; 23]

In F#, generics are a fundamental part of the language and are used extensively in the standard library and in user-defined types and functions. They provide type safety and code reuse, allowing you to write flexible and robust code that works with multiple types.