> module Kata where
> -- libraries
> import Text.Read (readMaybe)
> import qualified Data.List as List
> import qualified Data.Char as Char
> import qualified Data.Maybe as Maybe
This file starts by first declaring that we
are creating a module called Kata
and are using functions defined in the
modules
Data.List
Data.Char
Data.Maybe
and
Text.Read
The import from Text.Read
only brings the readMaybe
function into scope. All other
functions in that module are not available. However, the next three lines import all
functions from the respective modules, but makes them available with qualified names,
such as List.intersperse
, etc. We import them in this way so that you have the freedom
to use any functions from these modules in your solution to this problem.
> --------------------------------------------------------------------------------
> -- Data Munging Kata
> --------------------------------------------------------------------------------
A Code Kata is an exercise that helps an experienced programmer hone their skills. The coding exercise is usually not difficult---what is important is the analysis and design of the problem as well and the practice and repetition that lead to good coding habits. This exercise comes from website devoted to Code Katas and is not specific to Haskell.
This problem is an exercise in three parts to do with real world data. For that reason, we aren't expecting you to produce a robust solution. You can expect input that is in a similar format to the data files that we provide (same number and ordering of columns, same header and footer layout). However, your code should be able to deal with reasonable changes (different number of days in a month, different number of teams in the league).
However, remember that you shouldn't use partial functions. There shouldn't be
an input that causes your program to error. Definitely avoid functions such as
(!!)
, read
, or minimum
.
This problem also is about refactoring, so try hard not to read ahead---do each of the three parts below in turn and then reflect on your experience.
> -- Part One: Weather
In jul24.dat
(in the dat
subdirectory) you'll find daily weather data for
Philadelphia, PA for July 2024. This data is taken from
NOAA.
Your job is to write a program to output the day number (column one) with the smallest temperature spread (the maximum temperature is the second column, the minimum the third column). If there are multiple days with the same smallest spread, your program should return the first one.
> -- >>> weatherProgram "dat/jul24.dat"
> -- "12"
> -- >>> weatherProgram "dat/jul23.dat"
> -- "16"
We've given you the I/O parts of the program---opening the file and then
printing the final result. You need to write the weather
function below,
that takes the string containing the text of the file and processes it to find
the answer. Your program should work for any text file with the same format as
this one. If the format is different, and your program cannot parse the data,
then it should return Nothing
. (We will discuss better approaches to error
handling later in the semester.)
> weather :: String -> Maybe String
> weather str = error "unimplemented"
> weatherProgram :: String -> IO String
> weatherProgram file = do
> str <- readFile file
> return (case weather str of
> Just result -> result
> Nothing -> "Cannot read file")
Hints: You should use the words
and lines
functions from the Haskell
Prelude to split up the lines and columns in a manner that is robust to
whitespace characters. You should also use the (overloaded) Read.readMaybe
function to help you convert strings into integers. We've given it a new
name and type signature to make it easier for you to use.
> -- | Use this function to parse Ints
> readInt :: String -> Maybe Int
> readInt = readMaybe
> -- Part Two: Soccer League Table
The file dat/soccer22.dat
contains the results from the English Premier League
for the 2022/2023 season. This data is taken from
SkySports.The columns
labeled "W" and "L" contain the total number of wins and losses for
each team in that season (so Liverpool won 19 games against opponents and
lost nine). Write a program to find the name of the
team with the smallest (absolute) difference in "W" and "L". If there are multiple
teams with the smallest difference, your program should return the first one.
> -- >>> soccerProgram "dat/soccer23.dat"
> -- "West Ham United"
> soccer :: String -> Maybe String
> soccer = error "unimplemented"
> soccerProgram :: String -> IO String
> soccerProgram file = do
> str <- readFile file
> return $ case soccer str of
> Just result -> result
> Nothing -> "Cannot read file"
Your program should work with all similar input files (same columns, same info in footer).
> -- Part Three: DRY Fusion
Now, take the two programs written previously and factor out as much common code as possible, leaving you with two smaller programs and some kind of shared functionality.
> weather2 :: String -> Maybe String
> weather2 = undefined
> soccer2 :: String -> Maybe String
> soccer2 = undefined
> -- Kata Questions
Fill in the strings below with your answers.
> -- To what extent did the design decisions you made when writing the original
> -- programs make it easier or harder to factor out common code?
> shortAnswer1 :: String
> shortAnswer1 = "Fill in your answer here"
> -- Was the way you wrote the second program influenced by writing the first?
> shortAnswer2 :: String
> shortAnswer2 = "Fill in your answer here"
> -- Is factoring out as much common code as possible always a good thing? Did the
> -- readability of the programs suffer because of this requirement? How about the
> -- maintainability?
> shortAnswer3 :: String
> shortAnswer3 = "Fill in your answer here"