Let's implement a simple multiplication function in different languages, and examine the implications of each type.

JavaScript

function multiply(x, y) {
console.log('multiplying', x, 'and', y);
return x * y;
}

Let's find out what its type is.

console.log(typeof multiply);
// function

Welp, that doesn't tell us a whole lot.

Here's what we know from the type:

multiply is a function

Here's what we don't know from the type:

Whether multiply takes any arguments

What, if anything, multiply does with applied arguments

What, if anything, multiply returns

Whether multiply has any side effects, such as console.log(...) or exec('rm -rf /')

Scala

def multiply(x: Int, y: Int): Int = {
println(s"multiplying ${x} and ${y}")
x * y
}

Let's find out what type it is.

:t multiply _
// (Int, Int) => Int

This tells us a bit more.

Here's what we know from the type:

multiply is a function

multiply takes two Int arguments

multiply returns an Int value

Here's what we still don't know from the type:

What, if anything, multiply does with applied arguments

Whether multiply has any side effects, such as println(...) or "rm -rf /"

Haskell

multiply :: Int -> Int -> Int
multiply x y = x * y

We've declared its type to be Int -> Int -> Int. This tells us quite a lot.

Here's what we know from the type:

multiply is a function

multiply takes two Int arguments

multiply returns an Int value

multiply has no side effects, such as putStrLn ... or system "rm -rf /"

Here's what we still don't know from the type:

What, if anything, multiply does with applied arguments

Linear Haskell

multiply :: Int -o Int -o Int
multiply x y = x * y

In addition to the above, here's what we know from the type:

multiply uses both arguments exactly once

From the type, we don't know how the arguments are used (i.e. whether they are multiplied), but we do know that they are both used, and that they are each used only once.