Assignment 1 solutions

import Control.Monad.State -- Needed only for test code
  1. Rewrite the factorial function I defined above to use if-then-else instead of the pattern guard.
factIf n =
  if n <= 0 then 1
  else n * factIf (n-1)
  1. Define this mathematical function using Haskell, name it quadratic, and test it.

    \[q(a,b,c) = \frac{-b + \sqrt{b^2 - 4ac}}{2a} \]

quadratic a b c =
  (-b + sqrt(b^2 - 4*a*c))/(2*a)
  1. Define a function to calculate the volume of a sphere of a given radius. Name it sphere.
sphere r = (4/3) * pi * r^3
  1. Here is a recursive function in Haskell:
slow x y
  | x < y = x
  | otherwise = slow (x-y) y

Trace out the steps involved in evaluating slow 101 21, the same way we would for an algebraic expression. That is, determine the parameters x and y, check which case applies, then rewrite it.

  • slow 101 21 Substitute 101 for x, 21 for y. x < y is false, so use the otherwise case.
  • slow (101-21) 21 Subtract
  • slow 80 21 Substitute again, still otherwise
  • slow (80-21) 21 Subtract
  • slow 59 21 Substitute again, still otherwise
  • slow (59-21) 21 Subtract
  • slow 38 21 Substitute, still otherwise
  • slow (38-21) 21 Subtract
  • slow 17 21 Substitute, this time x < y
  • 17 So the answer is x.
  1. Write a recursive Haskell function collatzCount n that calculates the number of steps it takes to get from n down to 1.
collatzCount n
  | n <= 1 = 0
  | otherwise = 1 + collatzCount (collatz2 n)
collatz2 n | even n = n `div` 2
collatz2 n = 3*n + 1

Test driver

main = flip execStateT (0,0) $ do
  verify "fact 5"       120 $ factIf  5
  verify "fact 6"       720 $ factIf  6
  verify "fact10"   3628800 $ factIf 10
  verify "fact12" 479001600 $ factIf 12
  verifyF "quad 2 9 3"  (-0.36254139118231254) $ quadratic 2 9 3
  verifyF "quad 1 -1 -1"  1.618033988749895    $ quadratic 1 (-1) (-1)
  verifyF "quad 2 8 6"  (-1.0)                 $ quadratic 2 8 6
  verifyF "quad 1 30 π" (-0.1050878704703262)  $ quadratic 1 30 pi
  verifyF "sphere 1"      4.1887902047863905   $ sphere 1
  verifyF "sphere 3.75" 220.8932334555323      $ sphere 3.75
  verifyF "sphere 18.1" 24838.441017720263     $ sphere 18.1
  verifyF "sphere 21.2" 39349.20615723923      $ sphere 21.1
  verify "collatz  27" 111 $ collatzCount   27
  verify "collatz  99"  25 $ collatzCount   99
  verify "collatz1024"  10 $ collatzCount 1024
  verify "collatz 118"  33 $ collatzCount  118
  get >>= say . show
  where
    say = liftIO . putStrLn
    correct (k, n) = (k+1, n+1)
    incorrect (k, n) = (k, n+1)
    verify = verify' (==)
    verifyF = verify' (\x y -> abs(x-y) < 0.00001)
    verify' :: (Show a) => (a -> a -> Bool) -> String -> a -> a -> StateT (Int,Int) IO ()
    verify' eq tag expected actual
      | eq expected actual = do
          modify correct
          say $ " OK " ++ tag
      | otherwise = do
          modify incorrect
          say $ "ERR " ++ tag ++ ": expected " ++ show expected
            ++ " got " ++ show actual