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.