CMSI 386
Homework #5
Warmup.hs
```module Warmup
( change
, stripQuotes
, firstUppercasedOverLengthFive
, powers
, sumOfCubesOfOdds
, Shape (Box, Sphere)
, volume
, surfaceArea
) where

import Data.List
import Data.Char

change :: Int -> Either String (Int, Int, Int, Int)
change amount
| amount < 0 = Left "amount cannot be negative"
| otherwise =
let
(quarters, afterQuarters) = amount`divMod` 25
(dimes, afterDimes) = afterQuarters `divMod` 10
(nickels, pennies) = afterDimes `divMod`  5
in
Right (quarters, dimes, nickels, pennies)

stripQuotes :: String -> String
stripQuotes = filter (\c -> c /= '\'' && c /= '"')

-- This is a direct approach without any fancy monadic stuff
firstUppercasedOverLengthFive :: [String] -> Maybe String
firstUppercasedOverLengthFive ss = case find ((>5) . length) ss of
Just s -> Just (map toUpper s)
Nothing -> Nothing

powers :: Num a => a -> [a]
powers base = map (base^) [0..]

-- The approach with comprehensions
--     powers base = [base ^ i | i <- [0..]]
-- is not as good, IMHO, because the i feels redundant

sumOfCubesOfOdds :: Integral a => [a] -> a
sumOfCubesOfOdds numbers = sum [x ^ 3 | x <- numbers, (not . even) x]

-- I don't mind the comprehensions here. Map and filter is ALSO great:
-- sumOfCubesOfOdds xs = sum \$ map (^3) \$ filter (not . even) xs

data Shape
= Sphere Double
| Box Double Double Double
deriving (Eq, Show)

volume :: Shape -> Double
volume (Sphere r) = (4 / 3) * pi * (r ^ 3)
volume (Box w l d) = w * l * d

surfaceArea :: Shape -> Double
surfaceArea (Sphere r) = 4 * pi * (r ^ 2)
surfaceArea (Box w l d) = 2 * ((w * l) + (w * d) + (l * d))
```