Skip to content

DA6. Higher Order Functions and Lazy Evaluation

Task 1

Discuss the concept of lazy evaluation and why this is a powerful advantage of functional programs.

According to (Haskell Wiki, 2021), lazy evaluation is a strategy that delays the evaluation of an expression until its value is needed; that is, the evaluation is deferred from when the expression is bound to a variable to when the variable is actually used.

Relying on the characteristics of immutability and the absence of side effects that functional programming languages have, lazy evaluation is possible since the value of an expression is not going to change between the time it is bound to a variable and the time it is used.

Compared to the eager evaluation found in imperative programming languages, lazy evaluation allows bypassing the line-by-line execution of a program that eager evaluation requires as every line is dependent on all of the previous lines.

The advantages of lazy evaluation circulates around efficiency, as some program runs may not require the evaluation of all expressions, lazy evaluation may allow the program to run faster by evaluating less expressions.

  • Example 1: The following Haskell code will not evaluate the expression 1/0 as it is not used in the program.

    main = do
        let x = 1/0
        print "Hello World!"
    
  • Example 2: Infinite lists. The following Haskell code will not evaluate the expression take 5 [1..] as it is not used in the program; but if you used x the program will not run in infinite loop as it will only evaluate the first 5 elements of the infinite list.

    main = do
        let x = take 5 [1..]
        print "Hello World!"
    

One of the disadvantages of lazy evaluation is that it can be difficult to predict when an expression will be evaluated and then the to predict resource consumption becomes a difficult task.


Task 2

Describe and Discuss the concepts of Higher order functions and currying in a functional programming language such as Haskell (or Standard ML) and describe why these concepts are important.

Higher order functions are functions that take other functions as arguments or return functions as their results. This is a powerful concept that simplifies code interfaces by reducing the number of arguments that a function needs to take, and makes code reuse easier.

  • Example 3: The map function is a higher order function that takes a function and a list as arguments and returns a new list with the function applied to each element of the list.
inc :: Int -> Int
inc x = x + 1

main = do
    map inc [1..4] -- [2,3,4,5]

Currying is piping a sequence of functions so that the out of the previous function becomes the input of the next function. This is an important concept in functional programming as it allows the creation of functions with more than one argument.

  • Example 4: The add function is a curried function that takes two arguments and returns the sum of the two arguments (ComputerPhile, 2020).
add :: Int -> Int -> Int
add x y = x + y
adder x = \y -> x + y

main = do
    add 1 2 -- 3
    map (add 2) [1..4] -- [3,4,5,6]
    map (adder 2) [1..4] -- [3,4,5,6]

References