functional
Published in

functional

haskell functions

Haskell is a pure functional language. This means functions in Haskell behave closer to mathematical functions. A function operates on the input parameters and returns a result. Functions do not modify state.

Here we will be introducing Haskell functions by examples presented in the following code snippet.

simple functions and type inference

Let’s start with simple functions that accept a single input value and output a single result.

half

This function takes a single value x and transforms it into a value that is half of the input. Note that we did not specify any types here. Haskell infers the types. A :t command for the function reveals the following type signature.

Key points to note here are:

  • half is a function that accepts an input of type a and outputs a value of type a
  • Haskell has inferred the type a is constrained to the Fractional type class.
  • Since we did not explicitly specify a type for a, Haskell inferred the most general type that will support the function’s requirements.
  • A :info command on Fractional reveals that it mandates support for (/) operator function. This selection was based on the use of the / in the half function.

square

square uses the * operation. This results in an inferred type Num.

:i on Num shows us that Num requires the support of *.

areaCircle

The areaCircle function invokes the square function we had just defined.

Note that the inferred type class is now less general than square as the areaCircle uses the pi constant defined in Floating type class.

:i on Floating shows that it extends the Fractional type class. So, some generality has been lost here.

An important take away from the discussion above is that:

Haskell function definitions without explicit type specifications are as general as they possibly can be. Keeping functions as general as possible, promotes code reuse.

multi-parameter functions and currying

We have seen single parameter functions. How does Haskell support multi-parameter functions?

In Haskell all functions take only one argument. Multi-argument functions are formed by cascading multiple function applications. This is best explained with an example.

volumeCylinder

The above function appears to take two arguments, radius (r) and height (h).

The signature of the function is shown above. The first two arrows represent the radius and height parameters. The third arrow represents the return value. This is further clarified below.

It appears that the volumeCylinder function takes two parameters. Haskell however treats the above declaration as a cascade of two function applications:

  • volumeCylinder function takes radius (r) and returns a second function.
  • The second function takes the height as a parameter and returns the volume of the cylinder.

Strictly speaking, the volumeCylinder signature should be written as shown below.

Haskell implements functions this way to facilitate partial application. Partial application is explained by the gauge10Volume function that is formed by partially applying the parameters to the volumeCylinder function.

guage10Volume

Consider the above function that determines the volume of a gauge 10 cable of given length. The function’s body just consists of partial application of the volumeCylinder function with just the radius parameter. The gauge10Volume just takes the height parameter (length of the cable) and will return the volume of a gauge 10 cable.

operations

Operations like +, * are also functions. The operations can be invoked in the conventional infix operation a+b or as a function (+) a b.

You can learn more about the functions by issuing in the :i command in GHCI. You can see the function signatures as well as operator precedence.

recursive function defined using equations

Haskell supports parameter pattern matching in functions. You can specify multiple declarations of the same function with different parameter patterns. For example, the factorial function is shown below with two declarations:

  • factorial 0 specifies the factorial for the number 0
  • factorial n defines the factorial for all integers other than 0.

Also note the definition of factorial n is recursively defined in terms of factorial (n-1). Recursion is a very common pattern in functional programming. We will see it being used for function definitions, data structure definition and loops.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store