Some languages use the colon syntax, such as the Pascal family. Others, like Rust and Gleam, use the arrow syntax.
The arrow syntax meshes better with the idea that there's a difference between the types of values, and the meaning of a function signature. "foo: t" declares a name "foo" as having a type "t", but functions are abstractions — what is the "type" of factorial()? It's not "int".
The type of factorial() could be written:
(int) -> int
or just:
int -> int
If you look at the ML family as well as Haskell, that's exactly how they express it.
They do that for other reasons, too; those languages follow lambda calculus, which only has single-argument functions, so all functions are simply mappings between a single value to another value.
The arrow syntax meshes better with the idea that there's a difference between the types of values, and the meaning of a function signature. "foo: t" declares a name "foo" as having a type "t", but functions are abstractions — what is the "type" of factorial()? It's not "int".
The type of factorial() could be written:
or just: If you look at the ML family as well as Haskell, that's exactly how they express it.They do that for other reasons, too; those languages follow lambda calculus, which only has single-argument functions, so all functions are simply mappings between a single value to another value.