Function

Function #

Function definition #

Syntax. A function in Haskell is defined analogously to a mathematical function, with the symbol =.

Example. The function $f(x) = 2x$ is written:

f x = 2 * x

Warning. As opposed to Java (and C/C++, C#, Javascript, Python, etc.), the symbol = in Haskell does not assign a value to a variable.

Syntax. Note that $f(x)$ is written f x, without parentheses. This also holds when applying a function to a constant.

Example. $f(15)$ is normally written:

f 15

Function type #

Syntax. The type of a Haskell function is specified immediately above its definition, as follows:

<functionName> :: <type>

Example. The function $g\colon \mathbb{Z} \to \mathbb{Z}$ defined by $g(x) = x^2$ is written

g :: Integer -> Integer
g x = x^2

Warning. The type declaration and its definition must be aligned.

Example. The following declaration is not syntactically valid:

g :: Integer -> Integer
  g x = x^2   -- invalid indentation!!!

Warning. Haskell is sensitive to indentation in some contexts. If you do not understand why your code does not compile, then asking an LLM can be helpful.

Function types in Haskell are optional, but highly recommended.

Hint. Function types in Haskell can be automatically inferred.

So you may use them in two alternative ways:

  1. For a simple function:
  • implement the function,
  • then use your IDE to generate a type for it.
  1. For a more complex function:
  • write the function type,
  • then implement the function,
  • use your IDE (or the compiler) to check that your implementation meets the type requirements.

Note that the first option may produce a type that is too generic for your needs.

Alias #

Haskell provides several syntaxes to use aliases in function definitions.

<expression> where <alias definition> #

Example. The two following functions are equivalent (where ord :: Char -> Int maps a character to its Unicode number).

-- True iff the input character is an ASCII character
isAsciiChar :: Char -> Bool
isAsciiChar x = ord x >= 0 && ord x <= 127    -- the expression `ord x` is repeated

-- We introduce an alias `code` for `ord x`
isAsciiCharW :: Char -> Bool
isAsciiCharW x = code >= 0 && code <= 127
  where
    code = ord x   -- the alias is defined after it is used

let <alias definition> in <expression> #

Example. The following function is equivalent the ones above.

isAsciiCharL :: Char -> Bool
isAsciiCharL x =
  let code = ord x    -- the alias is defined before it is used
   in code >= 0 && code <= 127

Warning. In some contexts, only one of the two syntaxes (where or let) can be used. See details here.

Composition #

Syntax. The composition operator $\circ$ is written . in Haskell.

Example. The functions isAsciiChar2, isAsciiChar3 and isAsciiChar4 below are equivalent to the function isAsciiChar above.

-- auxiliary function that checks whether a number is within the ascii range
ascii :: Int -> Bool
ascii x = x >= 0 && x <= 127

isAsciiChar2 :: Char -> Bool
isAsciiChar2 x = ascii (ord x)

isAsciiChar3 :: Char -> Bool
isAsciiChar3 x = (ascii . ord) x

isAsciiChar4 :: Char -> Bool
isAsciiChar4 = ascii . ord

Terminology. Simplifying isAsciiChar3 into isAsciiChar4 is called an eta-reduction (in lambda calculus). Your IDE may suggest it.

The resulting definition is sometimes called point-free.

Identity function #

Syntax. Haskell provides an identity function called id. It is implemented as expected, with a type variable:

id :: a -> a
id x = x