Tonλ's blog May the λ be with you

Programming in haskell - ch4 - Defining Functions

by @ardumont on

In this chapter, we encounter:

  • conditional expressions
  • guarded equations
  • pattern matching (tuple, list, integer)
  • lambda expressions

halve

Using library functions, define a function halve :: [a] → ([a], [a]) that splits an even-lengthed list into two halves.

For example:

> halve [1, 2, 3, 4, 5, 6]

([1, 2, 3], [4, 5, 6])

The function splitAt already provides the means to split one list from a given position. Here our position is the half of the length of the list, which gives:

halve :: [a] -> ([a], [a])
halve xs = splitAt (length xs `div` 2) xs

Executing in the repl, we obtain:

*Ch4> halve [1, 2, 3, 4, 5, 6]
([1,2,3],[4,5,6])

safetail

Consider a function safetail :: [a] → [a] that behaves as the library function tail, except that safetail maps the empty list to itself, whereas tail produces an error in this case.

Define safetail using:

  • a conditional expression
  • guarded equations
  • pattern matching

Hint: make use of the library function null.

conditional expression

We need the conditional to discriminate between the empty list (null xs) and the non empty list. If we are not in the empty list case, we can take the tail of list.

Thus giving:

safetail1 :: [a] -> [a]
safetail1 xs = if null xs then [] else tail xs

Example:

*Ch4> safetail1 []
[]
*Ch4> safetail1 [1,2,3]
[2,3]

guarded equations

Same explanation as before:

safetail2 :: [a] -> [a]
safetail2 xs | null xs   = []
             | otherwise = tail xs

Example:

*Ch4> safetail2 []
[]
*Ch4> safetail2 [3,2,1]
[2,1]

pattern matching

Using pattern matching is more intuitive (or so I thought). Either the list is empty and then we return it directly. Either, the list follows the pattern of having a head (which we do not care about, thus using the _) and a tail (thus returning the tail).

Here is the definition:

safetail3 :: [a] -> [a]
safetail3 [] = []
safetail3 (_:xs) = xs

Example:

*Ch4> safetail3 []
[]
*Ch4> safetail3 [1,3,5,7,11]
[3,5,7,11]

Logical conjunction

In a similar way to , show how the logical conjunction operator can be defined in four different ways using pattern matching.

1st

Naive one:

orr :: Bool -> Bool -> Bool
orr False False = False
orr True True   = True
orr True False  = True
orr False True  = True

Check - Expected result: [False, True, True, True]

*Ch4> map (\ (f,s) -> orr f s) [(False, False), (False, True), (True, False), (True, True)]
[False,True,True,True]

OK

2nd

orr2 :: Bool -> Bool -> Bool
orr2 False False = False
orr2 _     _     = True

Check - Expected result: [False, True, True, True]

*Ch4> map (\ (f,s) -> orr2 f s) [(False, False), (False, True), (True, False), (True, True)]
[False,True,True,True]

OK

3d

orr3 :: Bool -> Bool -> Bool
orr3 False b     = b
orr3 b     False = b
orr3 _     _     = True

Check - Expected result: [False, True, True, True]

*Ch4> map (\ (f,s) -> orr3 f s) [(False, False), (False, True), (True, False), (True, True)]
[False,True,True,True]

OK

4th

orr4 :: Bool -> Bool -> Bool
orr4 False b = b
orr4 True  _ = True

Check - Expected result: [False, True, True, True]

*Ch4> map (\ (f,s) -> orr4 f s) [(False, False), (False, True), (True, False), (True, True)]
[False,True,True,True]

OK

Conjunction

Redefine the following version of the conjunction operator using conditional expressions rather than pattern matching:

True ∧ True = True

_ ∧ _ = False

and1 :: Bool -> Bool -> Bool
and1 a b = if not a
           then False
          else if not b
               then False
               else True

Not quite readable.

conditional expression 2

Do the same for the following version, and note the difference in the number of conditional expressions required:

True ∧ b = b

False ∧ _ = False

and3 :: Bool -> Bool -> Bool
and3 a b = if a
           then b
           else False

Curried function and lambda expression

Show how the curried function definition mult x y z = x ∗ y ∗ z can be understood in terms of lambda expressions.

Here it goes:

mult :: Int -> Int -> Int -> Int
mult = (\ x -> \ y -> \ z -> x * y * z)

Executing in the haskell repl:

*Ch4> mult 10 20 30
6000

Source

Latest posts