Programming

F# generic function

steloflute 2026. 5. 5. 22:45

In F#, generic functions allow you to write code that works with any data type while maintaining full type safety. Unlike languages where you might use object and cast types, F# uses Automatic Generalization to infer the most generic version of your code possible.


1. Automatic Generalization

Most of the time, you don't even need to use special syntax. If the compiler can’t find a reason to restrict a type, it makes it generic automatically.

F#
 
// F# infers this as: 'a -> 'a -> 'a * 'a
let swap a b = (b, a)

let result1 = swap 10 20          // Works with ints
let result2 = swap "Hello" "World" // Works with strings

In F#, generic type parameters are prefixed with a tick (e.g., 'a, 'T, 'Key).


2. Explicit Syntax

If you want to be explicit about your generics (useful for documentation or complex logic), you place the type parameters in angle brackets after the function name.

F#
 
let printValue<'T> (value: 'T) =
    printfn "The value is: %A" value

3. Generic Constraints

Sometimes you need a function to be generic, but only for types that support certain operations (like addition or comparison).

Common Constraints

Constraint Syntax Description
Comparison 'T : comparison Allows use of >, <, =, etc.
Equality 'T : equality Allows use of = and <>.
Null 'T : null Type must support the null literal.
Inlining (Static) inline Used for math operators like + or -.

Example: Comparison Constraint

F#
 
let findMax<'T when 'T : comparison> (a: 'T) (b: 'T) =
    if a > b then a else b

4. The inline Keyword (Statically Resolved Generics)

F# handles math differently. Because + is defined differently for int, float, and decimal, a standard generic function won't work for math unless you use inline.

F#
 
// This works for any type that supports the + operator
let inline add x y = x + y

let sumInt = add 5 10          // 15
let sumFloat = add 5.5 1.2     // 6.7

Note: inline tells the compiler to replace the function call with the actual function body at the call site, allowing it to resolve the specific math operator needed.


5. Generic Type Definitions

Generics aren't limited to functions; they are the backbone of F# data structures.

F#
 
type Result<'T> =
    | Success of 'T
    | Failure of string

let myNum = Success(42)
let myStr = Success("All good")

Summary Tips

  • Let the compiler help: Start without type annotations; F# is remarkably good at generalizing for you.
  • Check the Tooltip: Hover over your function name in your IDE. If you see 'a, it’s generic.
  • Use inline for Math: If you get an error saying a type doesn't support +, inline is usually the fix.