CSc 372 - Comparative Programming Languages
12 : Haskell -- Composing Functions

Christian Collberg

Department of Computer Science

University of Arizona

1 Composing Functions

We want to discover frequently occurring patterns of computation. These patterns are then made into (often higher-order) functions which can be specialized and combined. map f L and filter f L can be specialized and combined:


\begin{gprogram}
double :: [Int] -> [Int]\\
double xs = map ((*) 2) xs\\
\\
p...
...) xs) \\
\redtxt{? doublePos [2,3,0,-1,5]} \\
\mbox{[4, 6, 10]}
\end{gprogram}

2 Composing Functions...


\begin{gprogram}
infixr 9 . \\
(.) :: (b->c) -> (a->b) -> (a->c) \\
(f . g)(x) = f(g(x))
\end{gprogram}

3 Composing Functions...


\begin{gprogram}
(.) :: (b->c) -> (a->b) -> (a->c) \\
(f . g)(x) = f(g(x))
\end{gprogram}

Composition

4 Composing Functions...


\begin{gprogram}
doit x = f1 (f2 (f3 (f4 x))) \\
doit x = (f1 . f2 . f3 . f4) x \\
doit = f1 . f2 . f3 . f4
\end{gprogram}

\begin{gprogram}
\redtxt{? map (doit) xs} \\
\redtxt{? map (f1 . f2 . f3 . f4) xs}
\end{gprogram}

5 Example: Splitting Lines


\begin{gprogram}
fill :: string -> [string] \\
fill s = splitLines (splitWords s)
\end{gprogram}

\begin{gprogram}
splitWords :: string -> [word] \\
splitLines :: [word] -> [line]
\end{gprogram}

\begin{gprogram}
fill = splitLines . splitWords
\end{gprogram}

6 Precedence & Associativity

  1. "." is right associative. I.e.
    \begin{gprogram}
f.g.h.i.j = f.(g.(h.(i.j)))
\end{gprogram}
  2. "." has higher precedence (binding power) than any other operator, except function application:
    \begin{gprogram}
5 + f.g 6 = 5 + (f. (g 6))
\end{gprogram}
  3. "." is associative:
    \begin{gprogram}
f . (g . h) = (f . g) . h
\end{gprogram}
  4. "id" is "."'s identity element, i.e id . f = f = f . id:
    \begin{gprogram}
id :: a -> a \\
id x = x
\end{gprogram}

7 The count Function


\begin{gprogram}
\xx count 2 [[1],[],[2,3],[4,5],[]] $\Rightarrow$ 2
\end{gprogram}

Using recursion:
\begin{gprogram}
count :: Int -> [[a]] -> Int \\
count \_ [] = 0 \\
count n (x...
...xxxx = 1 + count n xs \\
\x \vert otherwise \xxxxxx = count n xs
\end{gprogram}

Using functional composition:
\begin{gprogram}
count' n = length . filter (==n) . map length
\end{gprogram}

8 The count Function...


\begin{gprogram}
count' n = length . filter (==n) . map length
\end{gprogram}

Count

9 The init & last Functions

Definitions:
\begin{gprogram}
last = head . reverse \\
\\
init = reverse . tail . reverse
\end{gprogram}

Simulations:
\begin{gprogram}
{[1,2,3]}$\stackrel{\tc{reverse}}{\Longrightarrow}$[3,2,1]$\sta...
...ightarrow}$
[2,1]$\stackrel{\tc{reverse}}{\Longrightarrow}$[1,2]
\end{gprogram}

10 The any Function


\begin{gprogram}
any ((==)0) [1,2,3,0,5] $\Rightarrow$ True \\
any ((==)0) [1,2,3,4] $\Rightarrow$ False
\end{gprogram}

Using recursion:
\begin{gprogram}
any :: (a -> Bool) -> [a] -> Bool \\
any \_ [] = False \\
any p (x:xs) = \= \vert p x = True \\
\x \vert otherwise = any p xs
\end{gprogram}

Using composition:
\begin{gprogram}
any p = or . map p \\
\redtxt{{[1,0,3]}$\stackrel{\tc{map ((==...
...dtxt{[False,True,False]$\stackrel{\tc{or}}{\Longrightarrow}$True}
\end{gprogram}

11 commaint Revisited...

From the commaint documentation:

[commaint] takes a single string argument containing a sequence of digits, and outputs the same sequence with commas inserted after every group of three digits, $\cdots$

12 commaint Revisited...

Sample interaction:
\begin{gprogram}
\redtxt{? commaint ''1234567''} \\
\x 1,234,567
\end{gprogram}

commaint in Haskell:
\begin{gprogram}
commaint = \= reverse . foldr1 ($\backslash$x y->x++'',''++y) ....
... takeWhile (not.null) . \\
\x \xx map (take n).iterate (drop n)
\end{gprogram}

13 commaint Revisited...

CommaInt

14 commaint Revisited...


\begin{gprogram}
commaint = \= reverse . foldr1 ($\backslash$x y->x++'',''++y) ....
... takeWhile (not.null) . \\
\x \xx map (take n).iterate (drop n)
\end{gprogram}

15 commaint Revisited...


\begin{gprogram}
commaint = \= reverse . foldr1 ($\backslash$x y->x++'',''++y) ....
... takeWhile (not.null) . \\
\x \xx map (take n).iterate (drop n)
\end{gprogram}

16 Lambda Expressions


\begin{gprogram}
commaint = $\cdots$ . foldr1 insert . $\cdots$ \\
\x where \= group n = $\cdots$ \\
\x \x insert x y = x++'',''++y
\end{gprogram}

Examples:
\begin{gprogram}
squareAll xs = map ($\backslash$ x -> x * x) xs \\
length = foldl' ($\backslash$n \_ -> n+1) 0
\end{gprogram}

17 Summary

18 Homework


\begin{gprogram}
\redtxt{? mid [1,2,3,4,5]} $\Rightarrow$ [2,3,4] \\
\redtxt{?...
...} $\Rightarrow$ ERROR \\
\redtxt{? mid [1,3]} $\Rightarrow$ []
\end{gprogram}



Christian S. Collberg
2005-09-19