Homework/HW3.fedorind.hs
2020-10-24 13:52:21 -07:00

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