Thinking Functionally with Haskell

Read Thinking Functionally with Haskell for Free Online

Book: Read Thinking Functionally with Haskell for Free Online
Authors: Richard Bird
definition.
    Here the two evaluation schemes result in the following sequence of reduction steps (we hide the steps involving simplification of the conditional expression to make another point):
factorial 3
factorial 3
= fact (3,1)
= fact (3,1)
= fact (3-1,3*1)
= fact (3-1,3*1)
= fact (2,3)
= fact (2-1,2*(3*1))
= fact (2-1,2*3)
= fact (1-1,1*(2*(3*1)))
= fact (1,6)
= 1*(2*(3*1))
= fact (1-1,1*6)
= 1*(2*3)
= fact (0,6)
= 1*6
= 6
= 6
    The point to appreciate is that, while the number of reduction steps is basically the same, lazy evaluation requires much more space to achieve the answer. The expression 1*(2*(3*1)) is built up in memory before being evaluated.
    The pros and cons of lazy evaluation are briefly as follows. On the plus side, lazy evaluation terminates whenever any reduction order terminates; it never takes more steps than eager evaluation, and sometimes infinitely fewer. On the minus side, it can require a lot more space and it is more difficult to understand the precise order in which things happen.
    Haskell uses lazy evaluation. ML (another popular functional language) uses eager evaluation. Exercise D explores why lazy evaluation is a Good Thing. Lazy evaluation is considered further in Chapter 7 .
    A Haskell function f is said to be strict if f undefined = undefined , and nonstrict otherwise. The function three is nonstrict, while (+) is strict in both arguments. Because Haskell uses lazy evaluation we can define nonstrict functions. That is why Haskell is referred to as a nonstrict functional language.
    Haskell has built-in (or primitive) types such as Int , Float and Char . The type Bool of boolean values is defined in the standard prelude: data Bool = False | True
    This is an example of a data declaration . The type Bool is declared to have two data constructors , False and True . The type Bool has three values, not two: False , True and undefined :: Bool . Why do we need that last value? Well, consider the function
    to :: Bool -> Bool
    to b = not (to b)
    The prelude definition of not is
    not :: Bool -> Bool
    not True = False
    not False = True
    The definition of to is perfectly wellformed, but evaluating to True causes GHCi to go into an infinite loop, so its value is ⊥ of type Bool . We will have much more to say about data declarations in future chapters.
    Haskell has built-in compound types, such as
    [Int] a list of elements, all of type Int (Int,Char) a pair consisting of an Int and a Char (Int,Char,Bool) a triple
    () an empty tuple
    Int -> Int a function from Int to Int
    The sole inhabitant of the type () is also denoted by () . Actually, there is a second member of () , namely undefined :: () . Now we can appreciate that there is a value ⊥ for every type.
    As we have already said, when defining values or functions it is always a good idea to include the type signature as part of the definition.
    Consider next the function take n that takes the first n elements of a list. This function made its appearance in the previous chapter. For example,
take 3 [1,2,3,4,5]
= [1,2,3]
take 3 "category"
= "cat"
take 3 [sin,cos]
= [sin,cos]
2.4 Types and type classes
    What type should we assign to take ? It doesn’t matter what the type of the elements of the list is, so take is what is called a polymorphic function and we denote its type by take :: Int -> [a] -> [a]
    The a is a type variable . Type variables begin with a lowercase letter. Type variables can be instantiated to any type.
    Similarly,
    (++) :: [a] -> [a] -> [a]
    map :: (a -> b) -> [a] -> [b]
    (.) :: (b -> c) -> (a -> b) -> (a -> c)
    The last line declares the polymorphic type of functional composition.
    Next, what is the type of (+) ? Here are some suggestions:
    (+) :: Int -> Int -> Int
    (+) :: Float -> Float -> Float
    (+) :: a -> a -> a
    The first two types seem too specific, while the last seems too general: we can’t add two functions or two characters or two booleans, at least not in any obvious way.
    The answer is to introduce type classes

Similar Books

Stretching Anatomy-2nd Edition

Arnold Nelson, Jouko Kokkonen

The Nonesuch

Georgette Heyer

Sinai Tapestry

Edward Whittemore

The Seventh Crystal

Gary Paulsen

A Man to Die for

Eileen Dreyer

The Fifth Harmonic

F. Paul Wilson

Mumbaistan

Piyush Jha