\documentclass{book}
\renewcommand{\chaptername}{Lecture}
\usepackage{amsmath}
\usepackage{ctable}
\usepackage[mathletters]{ucs}
\usepackage[utf8x]{inputenc}
\usepackage[breaklinks=true,unicode=true]{hyperref}
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}
%\setcounter{secnumdepth}{0}


\begin{document}

\setcounter{chapter}{17}

\chapter{Functions with varible number of arguments.}

Consider the printf function in C. The number of arguments it take
depends on the format string that is provided to it. Can one have
similar functions in Haskell ?

Let us analyse the type of \texttt{printf} in various expressions. In
the expression \texttt{printf "Hello"}, \texttt{printf} should have type
\texttt{String -\textgreater{} IO ()} where as in an expression like
\texttt{printf "Hello \%s" "world"}, it should have the type
\texttt{String -\textgreater{} String -\textgreater{} IO()}. This
chamelon like behaviour is what we need to define printf.

In this lecture we show how to hack Haskell's type class mechanism to
simulate such variable argument functions. The stuff we will do is
beyond Haskell 98 and hence we need to enable certain extensison. We do
it via the following compiler pragmas. The very first set of lines in
the source code if they are comments that start with \texttt{\{-\#} and
end with \texttt{\#-\}} are treated as compiler pragmas. In this case we
want to allow the extensions FlexibleInstances OverlappingInstances and
InvoherentInstances. One can also give these extensions at compile time;
to enable the extension Foo use the flag -XFoo at compile time.

Ofcourse it is difficult to remember all the extensions that you need
for this particular code to work. The easiest way to know what
extensions are required is to go ahead and use it in your file. GHC will
warn you with an appropriate error message if it expects an extension.

\begin{verbatim}

> {-# LANGUAGE FlexibleInstances        #-}
> {-# LANGUAGE OverlappingInstances     #-}
> {-# LANGUAGE IncoherentInstances      #-}
>
> module Printf where
\end{verbatim}
Recall that an expression using printf would look something like the one
below.

\begin{verbatim}

printf fmt e1 e2 ... em
\end{verbatim}
We want our type system to infer \texttt{IO ()} for this expression. The
type of \texttt{printf} in such a case should be
\texttt{String -\textgreater{} t1 -\textgreater{} ... -\textgreater{} tm -\textgreater{} IO ()}
where \texttt{ti} is the type of \texttt{ei}. The main idea is to define
a type classes say \texttt{Printf} whose instances are precisely those
types that are of the form
\texttt{t1 -\textgreater{} ... -\textgreater{} tm -\textgreater{} IO ()}.
As a base case we will define an instance for \texttt{IO ()}. We will
then inductively define it for other types.

The definition of the type class \texttt{Printf} and therefore
\texttt{printf} will be easier if we first declare a data type for
formating.

\begin{verbatim}

>
> data Format = L String -- ^ A literal string
>             | S        -- ^ %s
>             | G        -- ^ %g for instances of Show
>
>
\end{verbatim}
We would rather work with the more convenient \texttt{{[}Format{]}}
instead of the format string. Writing a function to convert from format
string to \texttt{{[}Format{]}} is not too difficult.

Now for the actual definition of the \texttt{Printf} class.

\begin{verbatim}

> class Printf s where
>       printH :: IO [Format] -> s
>
\end{verbatim}
The member function \texttt{printH} of the class \texttt{Printf} is a
helper function that will lead us to definition of \texttt{printf}.
Intutively it takes as argument an IO action which prints whatever
arguments it has seen so far and returns the rest of the formating
action required to carry out s.

We will define the \texttt{Printf} instances for each of the type
\texttt{t1 -\textgreater{} ... tm -\textgreater{} I0 ()} inductively.
The base case is when there are no arguments.

\begin{verbatim}

> instance Printf (IO ()) where
>       printH fmtIO  = do fmt <- printLit fmtIO
>                          if null fmt then return ()
>                             else fail "Too few arguments provided"
>
\end{verbatim}
Now the inductive instance declaration.

\begin{verbatim}

> instance (Printf s, Show a) => Printf (a -> s) where
>          printH fmtIO a = printH action
>                 where action = do rfmt <- printLit fmtIO
>                                   case rfmt of
>                                        []     -> fail "Too many argument"
>                                        (_:xs) -> do putStr $ show a; return xs
\end{verbatim}
We give a specialised instance for string which depending on whether the
formating character is \%s or \%g uses putStr or print.

\begin{verbatim}

>
> instance Printf s => Printf (String -> s) where
>          printH fmtIO s = printH action
>                 where action = do rfmt <- printLit fmtIO
>                                   case rfmt of
>                                        [] -> fail "Too many arguments"
>                                        (G:xs) -> do putStr $ show s; return xs
>                                        (S:xs) -> do putStr s; return xs
>
\end{verbatim}
What is remaining is to define printLit

\begin{verbatim}

>
> printLit fmtIO = do fmt <- fmtIO
>                     let (lits,rest) = span isLit fmt
>                         in do sequence_ [putStr x | L x <- lits]
>                               return rest
> isLit (L _) = True
> isLit  _    = False
>
\end{verbatim}
We can now define printf

\begin{verbatim}

> printf :: Printf s => String -> s
> printf = printH . format
>
> format :: String -> IO [Format]
> format ""         = return []
> format "%"        = fail "incomplete format string"
> format ('%':x:xs) = do fmts <- format xs
>                        case x of
>                             's' -> return (S:fmts)
>                             'g' -> return (G:fmts)
>                             '%' -> return (L "%" :fmts)
>                             _   -> fail ("bad formating character %" ++ [x])
> format zs = let (lit,xs) = span (/='%') zs
>             in do fmts <- format xs
>                   return (L lit:fmts)
>
\end{verbatim}

\end{document}
