196 lines
3.6 KiB
Haskell
196 lines
3.6 KiB
Haskell
module HW3 where
|
|
|
|
import Prelude hiding (Enum(..), sum)
|
|
import Data.List (group)
|
|
import Data.Bifunctor (Bifunctor(second))
|
|
|
|
--
|
|
-- * Part 1: Run-length lists
|
|
--
|
|
|
|
-- | Convert a regular list into a run-length list.
|
|
--
|
|
-- >>> compress [1,1,1,2,3,3,3,1,2,2,2,2]
|
|
-- [(3,1),(1,2),(3,3),(1,1),(4,2)]
|
|
--
|
|
-- >>> compress "Mississippi"
|
|
-- [(1,'M'),(1,'i'),(2,'s'),(1,'i'),(2,'s'),(1,'i'),(2,'p'),(1,'i')]
|
|
--
|
|
compress :: Eq a => [a] -> [(Int,a)]
|
|
compress = map ((>>=id) $ fmap ((second head) .) (,) . length) . group
|
|
|
|
-- Yeah this isn't so good pointfree.
|
|
-- I don't normally write code like this, believe me.
|
|
--
|
|
-- So we have:
|
|
-- >>= id = join :: m (m a) -> m a = (a -> a -> b) -> a -> b
|
|
-- temp1 = (,) . length :: [a] -> [a] -> (Int, [a])
|
|
-- (make a tuple and find the length)
|
|
-- temp2 = fmap ((second head) .) temp1 :: [a] -> [a] -> (Int, a)
|
|
-- (transform the tuple's second element into its head)
|
|
-- temp3 = join temp2 :: [a] -> (Int, a)
|
|
-- (ensure both parts of the tuple are the same list)
|
|
|
|
-- | Convert a run-length list back into a regular list.
|
|
--
|
|
-- >>> decompress [(5,'a'),(3,'b'),(4,'c'),(1,'a'),(2,'b')]
|
|
-- "aaaaabbbccccabb"
|
|
--
|
|
decompress :: [(Int,a)] -> [a]
|
|
decompress = concatMap (uncurry replicate)
|
|
|
|
|
|
--
|
|
-- * Part 2: Natural numbers
|
|
--
|
|
|
|
-- | The natural numbers.
|
|
data Nat
|
|
= Zero
|
|
| Succ Nat
|
|
deriving (Eq,Show)
|
|
|
|
fold :: a -> (a -> a) -> Nat -> a
|
|
fold b f Zero = b
|
|
fold b f (Succ n) = f (fold b f n)
|
|
|
|
-- | The number 1.
|
|
one :: Nat
|
|
one = Succ Zero
|
|
|
|
-- | The number 2.
|
|
two :: Nat
|
|
two = Succ one
|
|
|
|
-- | The number 3.
|
|
three :: Nat
|
|
three = Succ two
|
|
|
|
-- | The number 4.
|
|
four :: Nat
|
|
four = Succ three
|
|
|
|
|
|
-- | The predecessor of a natural number.
|
|
--
|
|
-- >>> pred Zero
|
|
-- Zero
|
|
--
|
|
-- >>> pred three
|
|
-- Succ (Succ Zero)
|
|
--
|
|
pred = snd . fold (id, Zero) ((,) Succ . uncurry ($))
|
|
|
|
|
|
-- | True if the given value is zero.
|
|
--
|
|
-- >>> isZero Zero
|
|
-- True
|
|
--
|
|
-- >>> isZero two
|
|
-- False
|
|
--
|
|
isZero = fold True (const False)
|
|
|
|
|
|
-- | Convert a natural number to an integer. NOTE: We use this function in
|
|
-- tests, but you should not use it in your other definitions!
|
|
--
|
|
-- >>> toInt Zero
|
|
-- 0
|
|
--
|
|
-- >>> toInt three
|
|
-- 3
|
|
--
|
|
toInt = fold 0 (+1)
|
|
|
|
|
|
-- | Add two natural numbers.
|
|
--
|
|
-- >>> add one two
|
|
-- Succ (Succ (Succ Zero))
|
|
--
|
|
-- >>> add Zero one == one
|
|
-- True
|
|
--
|
|
-- >>> add two two == four
|
|
-- True
|
|
--
|
|
-- >>> add two three == add three two
|
|
-- True
|
|
--
|
|
add = flip fold Succ
|
|
|
|
|
|
-- | Subtract the second natural number from the first. Return zero
|
|
-- if the second number is bigger.
|
|
--
|
|
-- >>> sub two one
|
|
-- Succ Zero
|
|
--
|
|
-- >>> sub three one
|
|
-- Succ (Succ Zero)
|
|
--
|
|
-- >>> sub one one
|
|
-- Zero
|
|
--
|
|
-- >>> sub one three
|
|
-- Zero
|
|
--
|
|
sub = flip $ fold id ((pred.))
|
|
|
|
-- | Is the left value greater than the right?
|
|
--
|
|
-- >>> gt one two
|
|
-- False
|
|
--
|
|
-- >>> gt two one
|
|
-- True
|
|
--
|
|
-- >>> gt two two
|
|
-- False
|
|
--
|
|
gt = fmap (fmap (not . (==Zero))) sub
|
|
|
|
-- | Multiply two natural numbers.
|
|
--
|
|
-- >>> mult two Zero
|
|
-- Zero
|
|
--
|
|
-- >>> mult Zero three
|
|
-- Zero
|
|
--
|
|
-- >>> toInt (mult two three)
|
|
-- 6
|
|
--
|
|
-- >>> toInt (mult three three)
|
|
-- 9
|
|
--
|
|
mult = fold Zero . add
|
|
|
|
|
|
-- | Compute the sum of a list of natural numbers.
|
|
--
|
|
-- >>> sum []
|
|
-- Zero
|
|
--
|
|
-- >>> sum [one,Zero,two]
|
|
-- Succ (Succ (Succ Zero))
|
|
--
|
|
-- >>> toInt (sum [one,two,three])
|
|
-- 6
|
|
--
|
|
sum :: [Nat] -> Nat -- Monomorphism restriction hits here
|
|
sum = foldl add Zero
|
|
|
|
|
|
-- | An infinite list of all of the *odd* natural numbers, in order.
|
|
--
|
|
-- >>> map toInt (take 5 odds)
|
|
-- [1,3,5,7,9]
|
|
--
|
|
-- >>> toInt (sum (take 100 odds))
|
|
-- 10000
|
|
--
|
|
odds = one : map (Succ . Succ) odds
|