Haskell logo CIS 5520: Advanced Programming

Fall 2024

  • Home
  • Schedule
  • Homework
  • Resources
  • Software
  • Style guide
> 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"
Design adapted from Minimalistic Design | Powered by Pandoc and Hakyll