liveBook · Manning

Type signature

As explained in F# in Action: A Revised Edition of Get Programming with F#

A type signature is a notation describing the types that make up a value or expression, including the structure of composite types.

A type signature is a compact description of a value or function’s types. For a function, types appear from left to right: input types first, then the result after the final arrow. For example, int -> int -> int describes a function taking two integers and returning an integer. Type annotations can make those types explicit, while F# type inference can often determine them automatically. section 3.2.2

Read signatures as a chain of inputs and result

The signature int -> int -> int can be read as “take an int, then take another int, then produce an int.” Parentheses disambiguate argument annotations: let add (a:int) (b:int) : int = a + b. Without parentheses, a trailing : int denotes the function’s return type rather than an argument’s type. section 3.2.2

Signatures also reveal how functions compose. List.map has the signature ('T -> 'U) -> 'T list -> 'U list: it needs a conversion function from 'T to 'U, then a list of 'T, and produces a list of 'U. Reading each arrow-separated part makes it easier to choose collection functions that fit together instead of trying combinations at random. section 7.2.3

mapping : ('T -> 'U) -> 'T list -> 'U list

Inspect the generic List.map signature, then match its first input to a conversion function and its second input to a source list. section 7.2.3

A signature can expose an important design choice—or conceal one. A mutable drive function typed string -> unit visibly accepts only a distance and returns no useful value, yet it also depends on and changes hidden gas state. Passing gas explicitly produces a function whose inputs and returned state are visible, making call order and behavior easier to follow. section 4.2.3

Signatures show partial application

An F# function written with two apparent inputs is a chain of single-input functions. add has int -> int -> int; after let addFive = add 5, addFive has int -> int; after addFive 10, the result has type int. The arrows explain why supplying one argument returns another function. section 6.1.1

How F# in Action: A Revised Edition of Get Programming with F# covers it

How deep it goes
Breaks down arrow-separated inputs, return types, generic list types, inference, and curried intermediate signatures.
Examples
Uses annotated addition, List.map over integers, partially applied add, and mutable versus explicit gas-state driving.
What it assumes
Introduces basic annotations and inference from zero, while deferring detailed function treatment until later.
What you can do after
Evaluate/understand F# function and collection APIs by reading their input, output, generic, and partial-application types.
How it connects
Connects type signatures to type inference, type annotations, List.map, higher-order functions, currying, partial application, and mutable state.

Also explained in

Compare how 8 books explain type signature →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of F# in Action: A Revised Edition of Get Programming with F#. The section links point to the parts of the book it draws on.