So languages are characterized by grammars.
Regarding the three linguistic layers of characters, words, and sentences:
While this layering is descriptive in a natural language, it is prescriptive in a programming language.
In emacs, typing M-x run-ocaml starts a read-eval-print loop (also known as a toplevel loop) where one types an OCaml expression, punctuated by ;; and the Enter key; the systems then reads this expression. Then, to a first approximation:
Typing C-c C-d stops OCaml.
OCaml is a language of expressions.
Through the toplevel loop, these expressions are evaluated and yield values. These values have a type: integer, boolean, string, etc.
This notion of type is not only specific to values: it characterizes the expressions that gave rise to these values.
Furthermore, this notion of type is not only specific to OCaml expressions: it characterizes the OCaml programming language itself.
Well-typed programs cannot go wrong.
OCaml is a statically typed programming language in that only expressions that are syntactically correct and that are type-correct too are evaluated. All the other expressions (i.e., the syntactically incorrect expressions and the syntactically correct but type-incorrect expressions) are rejected. The benefit of this syntactic discipline is that only grammatically correct expressions are considered (which avoids a world of confusions). The benefit of this typing discipline is that running an OCaml program never gives rise to a type error.
Type systems have been developed “bottom up”, i.e., as increased abstractions of desired computational behaviors. So it is something of a surprise that they also have a logical content, but this topic is out of scope here.
To quote the Wikipedia entry about binary relations, in mathematics, a binary relation over two sets A and B is a set of ordered pairs (a, b) consisting of elements a in A and b in B.
For example, the relation “is greater than” over the set of integers Z is the set of pairs of integers (i, j) for which there exists a positive integer k such that i = j + k. This particular relation is often represented using a set comprehension: {(i, j) | i belongs to the set of integers Z, j belongs to Z, and there exists a positive integer k such that i = j + k}.
To quote the Wikipedia entry about functions, in mathematics, a function is a relation between two sets – the domain of the function and its codomain – that maps each element of the domain to at most one element of the codomain.
Examples:
A function is often represented with its graph in that the pairs in its relation are the Cartesian coordinates of points in the Euclidean plane, a geometric rendition of the enumeration of these pairs. For example, the successor function over natural numbers is enumerated with {(0, 1), (1, 2), (2, 3), ...} and the square function over natural numbers with {(0, 0), (1, 1), (2, 4), (3, 9), ...}.
A predicate is a function whose codomain is the set of Booleans.
Examples:
A function is total when it maps each element of its domain to one element of its codomain. The successor function over natural numbers, for example, is total.
A function is partial when it does not map each element of its domain to an element of its codomain. The predecessor function over natural numbers, for example, is partial because while it maps any natural number n+1 to n, it does not map 0 to any natural number. For another example, a function that is only defined over non-negative integers is also partial.
Macroscopically, programs compute functions that map input data to output data.
Microscopically, we can implement functions in OCaml.
Added the reminders about relations and functions [02 Apr 2020]
Added the quote by Robin Milner [31 Jan 2020]
Fixed a typo in the narrative, thanks to Yunjeong Lee’s eagle eye [30 Mar 2019]
Created [28 Jan 2019]