Not logged in. Login

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-in iterate.
  • Write a recursive function mySplitAt that behaves identically to the built-in splitAt (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.

Updated Fri April 28 2023, 10:19 by ggbaker.