Exercise 5
For this exercise, put all of your function definitions in a file exer5.hs
. You must include an appropriate type declaration (::
) for each function you define in your exer5.hs
.
Built-In Functions
There are many useful functions that come with the language, but most of them are actually fairly simple to implement recursively. Let's prove that by doing a few.
- Write a recursive function
myIterate
that behaves identically to the built-initerate
. - Write a recursive function
mySplitAt
that behaves identically to the built-insplitAt
(except don't worry about the position<0 case).
Rational Numbers
In the Haskell standard library, there is a module Data.Ratio
that can be used to be represent rational numbers with the type Ratio Int
. A Ratio Int
value can be constructed with the %
operator: 2%7
represents the fraction 2/7.
Write a function rationalSum
that produces a list of all rational numbers whose numerator and denominator add to the given argument.
*Main> rationalSum 5
[1 % 4,2 % 3,3 % 2,4 % 1]
*Main> rationalSum 8
[1 % 7,1 % 3,3 % 5,1 % 1,5 % 3,3 % 1,7 % 1]
*Main> rationalSum 1
[]
Note that rational values are displayed in lowest-terms. The values displayed in the above example for rationalSum 8
are \(\frac{1}{7}\), \(\frac{2}{6}=\frac{1}{3}\), \(\frac{3}{5}\), \(\frac{4}{4}=\frac{1}{1}\), \(\frac{5}{3}\), \(\frac{6}{2}=\frac{3}{1}\), \(\frac{7}{1}\).
Lowest Terms Only
Make another version of the above function called rationalSumLowest
that produces the same fractions, but only the values are are already in lowest-terms.
*Main> rationalSumLowest 5
[1 % 4,2 % 3,3 % 2,4 % 1]
*Main> rationalSumLowest 8
[1 % 7,3 % 5,5 % 3,7 % 1]
*Main> rationalSumLowest 12
[1 % 11,5 % 7,7 % 5,11 % 1]
Hint: there is a built-in function gcd
that calculates the greatest common divisor of its arguments.
All Rational Numbers
Use the rationalSumLowest
function to construct a list rationals
that contains all positive rational numbers exactly once.
*Main> take 20 rationals
[1 % 1,1 % 2,2 % 1,1 % 3,3 % 1,1 % 4,2 % 3,3 % 2,4 % 1,1 % 5,5 % 1,1 % 6,2 % 5,3 % 4,4 % 3,5 % 2,6 % 1,1 % 7,3 % 5,5 % 3]
*Main> elem (8%7) rationals
True
*Main> elem (8%16) rationals
True
*Main> elem (251%1237) rationals -- make take a few seconds
True
*Main> elem (-1%2) rationals
-- infinite loop
If you actually do something infinite, you can press control-C to stop a runaway calculation.
[With any luck, you are now convinced that the set of integers and set of rational numbers have the same cardinality, but that's another course.]
Input/Output
Write a function sumFile :: IO ()
that reads a file input.txt
. The file will contain integers, one per line. You should add up the numbers and print
the result. Use my sample input.txt
if you like.
*Main> sumFile
164
[I know that returning and printing look the same in GHCi, but trust me: this prints.]
Hints: readFile
; write a function that splits a string into lines (around the '\n'
character); the function read
will convert a string to an integer as long as you're explicit about the type you want returned; as said in lecture, keep as much logic as possible away from the monad.
Here are some hints that may be useful:
-- split a list around a given separator value
splitAtSeparator :: Eq a => a -> [a] -> [[a]]
splitAtSeparator sep [] = []
splitAtSeparator sep content = first : splitAtSeparator sep rest
where
first = takeWhile (/= sep) content
firstlen = length first
rest = drop (firstlen+1) content
-- convert an integer-like string to an integer
readInt :: String -> Int
readInt = read
Submitting
Submit your files through CourSys for Exercise 5.