Skip to content

Commit 76970c2

Browse files
committed
start moving code into standalone .hs files
1 parent 92e92c1 commit 76970c2

File tree

6 files changed

+65
-54
lines changed

6 files changed

+65
-54
lines changed

CPiH.tex

Lines changed: 16 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -206,21 +206,7 @@ \section{A basic solution pipeline}
206206

207207
\begin{figure}
208208
\centering
209-
\begin{minted}{haskell}
210-
import Control.Arrow ((>>>))
211-
212-
main = interact $ parse >>> map solve >>> format
213-
214-
parse :: String -> [[Integer]]
215-
parse = _
216-
217-
solve :: [Integer] -> Integer
218-
solve = _
219-
220-
format :: [Integer] -> String
221-
format = _
222-
\end{minted}
223-
% $
209+
\inputminted{haskell}{code/intro/Skeleton.hs}
224210
\caption{A skeleton solution for A Different Problem}
225211
\label{fig:skeleton-different}
226212
\end{figure}
@@ -299,10 +285,7 @@ \section{Parsing and formatting}
299285

300286
\begin{figure}
301287
\centering
302-
\begin{minted}{haskell}
303-
parse :: String -> [[Integer]]
304-
parse = lines >>> map (words >>> map read)
305-
\end{minted}
288+
\inputminted[firstline=5, lastline=6]{haskell}{code/intro/Different.hs}
306289
\caption{\h{parse} function for A Different Problem}
307290
\label{fig:parse-different}
308291
\end{figure}
@@ -347,6 +330,8 @@ \section{Parsing and formatting}
347330
need to use provided information about the length of each test case.
348331
We will discuss such parsing in \pref{chap:parsing}.
349332

333+
\todo{include full solution for A Different Problem?}
334+
350335
\section{Using partial functions}
351336
\label{sec:partial}
352337

@@ -429,22 +414,13 @@ \section{Example: processing a list of strings}
429414
the list of words, updating an accumulator variable every time we see
430415
a string that does not contain the letter e. An inexperienced
431416
Haskeller might produce something similar:
432-
\begin{minted}{haskell}
433-
lengthWithoutE :: [String] -> Int
434-
lengthWithoutE [] = 0
435-
lengthWithoutE (s:ss)
436-
| 'e' `elem` s = lengthWithoutE ss
437-
| otherwise = length s + lengthWithoutE ss
438-
\end{minted}
417+
\inputminted{haskell}{code/wholemeal/LengthWithoutE.hs}
439418
This code works, but there is a better way. Instead of thinking in
440419
terms of processing the list one item at a time, an experienced
441420
Haskeller will think in terms of incrementally transforming the input
442421
into the desired output: first, filter out the strings we don't want;
443422
next, turn each string into its length; and finally sum the lengths.
444-
\begin{minted}{haskell}
445-
lengthWithoutE' :: [String] -> Int
446-
lengthWithoutE' = filter ('e' `notElem`) >>> map length >>> sum
447-
\end{minted}
423+
\inputminted{haskell}{code/wholemeal/LengthWithoutEWholemeal.hs}
448424
This is better in almost every way: it is shorter, easier to read and
449425
understand, easier to refactor, harder to get wrong, and easier to
450426
prove correct.
@@ -494,6 +470,9 @@ \subsection{Lists}
494470
lists with $10^5$ elements each is probably fine; having $10^5$ lists
495471
with two elements each is probably going to be too slow.
496472

473+
\todo{pick two or three representative sample problems and discuss
474+
their solutions? One using scanl?}
475+
497476
\kattis{foo, bar}
498477

499478
\subsection{Sets}
@@ -546,26 +525,7 @@ \subsubsection{Example: Booking a Room}
546525

547526
\begin{figure}
548527
\centering
549-
\begin{minted}{haskell}
550-
import Control.Arrow ((>>>))
551-
import qualified Data.Set as S
552-
553-
main :: IO ()
554-
main = interact $ words >>> parse >>> solve
555-
556-
data Hotel = Hotel
557-
{ numRooms :: Int
558-
, booked :: [Int]
559-
}
560-
561-
parse :: [String] -> Hotel
562-
parse (r:_:rs) = Hotel (read r) (map read rs)
563-
564-
solve :: Hotel -> String
565-
solve (Hotel r rs) =
566-
maybe "too late" show . S.lookupMin
567-
$ S.fromList [1..r] `S.difference` S.fromList rs
568-
\end{minted}
528+
\inputminted{haskell}{code/wholemeal/BookingARoom.hs}
569529
\caption{Booking a Room solution}
570530
\label{fig:bookingaroom}
571531
\end{figure}
@@ -1001,10 +961,12 @@ \section{ByteString}
1001961
\end{minted}
1002962
Now we're talking---this version completes in a blazing 0.04 seconds!
1003963
1004-
% We can take these principles and use them to make a variant of the
1005-
% `Scanner` module from last time which uses (lazy, ASCII) `ByteString`
1006-
% instead of `String`, including the use of the `readInt` functions to
1007-
% read `Int` values quickly. You can [find it here](https://github.com/byorgey/comprog-hs/blob/master/ScannerBS.hs).
964+
We can take these principles and use them to make a variant of the
965+
\h{Scanner} module from last time which uses (lazy, ASCII)
966+
\h{ByteString} instead of \h{String}, including the use of the
967+
\h{readInt} functions to read \h{Int} values quickly. You can [find
968+
it
969+
here](https://github.com/byorgey/comprog-hs/blob/master/ScannerBS.hs).
1008970
1009971
\chapter{Monoids}
1010972
\label{chap:monoids}

code/intro/Different.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Control.Arrow ((>>>))
2+
3+
main = interact $ parse >>> map solve >>> format
4+
5+
parse :: String -> [[Integer]]
6+
parse = lines >>> map (words >>> map read)
7+
8+
solve :: [Integer] -> Integer
9+
solve [a,b] = abs (a - b)
10+
11+
format :: [Integer] -> String
12+
format = map show >>> unlines

code/intro/Skeleton.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Control.Arrow ((>>>))
2+
3+
main = interact $ parse >>> map solve >>> format
4+
5+
parse :: String -> [[Integer]]
6+
parse = _
7+
8+
solve :: [Integer] -> Integer
9+
solve = _
10+
11+
format :: [Integer] -> String
12+
format = _

code/wholemeal/BookingARoom.hs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Control.Arrow ((>>>))
2+
import qualified Data.Set as S
3+
4+
main :: IO ()
5+
main = interact $ words >>> parse >>> solve
6+
7+
data Hotel = Hotel
8+
{ numRooms :: Int
9+
, booked :: [Int]
10+
}
11+
12+
parse :: [String] -> Hotel
13+
parse (r:_:rs) = Hotel (read r) (map read rs)
14+
15+
solve :: Hotel -> String
16+
solve (Hotel r rs) =
17+
maybe "too late" show . S.lookupMin
18+
$ S.fromList [1..r] `S.difference` S.fromList rs

code/wholemeal/LengthWithoutE.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
lengthWithoutE :: [String] -> Int
2+
lengthWithoutE [] = 0
3+
lengthWithoutE (s:ss)
4+
| 'e' `elem` s = lengthWithoutE ss
5+
| otherwise = length s + lengthWithoutE ss
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lengthWithoutE' :: [String] -> Int
2+
lengthWithoutE' = filter ('e' `notElem`) >>> map length >>> sum

0 commit comments

Comments
 (0)