Advertisement
Guest User

Untitled

a guest
Aug 22nd, 2017
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 1.58 KB | None | 0 0
  1. module IRV where
  2.  
  3. import Control.Monad (guard)
  4. import Data.List (nub, sortBy)
  5. import Data.Maybe (catMaybes, fromMaybe)
  6. import Data.Ord (Down(..), comparing)
  7.  
  8. winner :: Eq a => [[a]] -> Maybe a
  9. winner votes = do
  10. let freqs = frequencies votes
  11. candidate <- majorityCandidate freqs
  12. if hasAbsoluteMajority candidate freqs
  13. then return candidate
  14. else do
  15. last <- lastCandidate freqs
  16. winner (removeFirstPref last votes)
  17.  
  18. frequencies :: Eq a => [[a]] -> [(a, Int)]
  19. frequencies votes = group firstPreferences
  20. where firstPreferences = catMaybes (map maybeHead votes)
  21.  
  22. group :: Eq a => [a] -> [(a, Int)]
  23. group xs = map count (nub xs)
  24. where count x = (x, length (filter (x ==) xs))
  25.  
  26. maybeHead :: [a] -> Maybe a
  27. maybeHead [] = Nothing
  28. maybeHead xs = Just (head xs)
  29.  
  30. majorityCandidate :: Eq a => [(a, Int)] -> Maybe a
  31. majorityCandidate freqs = fst <$> maybeHead (sortBy (comparing (Down . snd)) freqs)
  32.  
  33. hasAbsoluteMajority :: Eq a => a -> [(a, Int)] -> Bool
  34. hasAbsoluteMajority candidate freqs = candidateVotes > totalVotes `div` 2
  35. where candidateVotes = fromMaybe 0 (lookup candidate freqs)
  36. totalVotes = sum (map snd freqs)
  37.  
  38. lastCandidate :: Eq a => [(a, Int)] -> Maybe a
  39. lastCandidate [] = Nothing
  40. lastCandidate [x] = Nothing
  41. lastCandidate [x, y]
  42. | snd x == snd y = Nothing -- It's a tie!
  43. lastCandidate freqs = fst <$> maybeHead (sortBy (comparing snd) freqs)
  44.  
  45. removeFirstPref :: Eq a => a -> [[a]] -> [[a]]
  46. removeFirstPref candidate = map removeFirstPref'
  47. where removeFirstPref' [] = []
  48. removeFirstPref' prefs@(x:xs)
  49. | x == candidate = xs
  50. | otherwise = prefs
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement