Use a type synonym for names and an algebraic data type with the two teams and their goals in the given positional order:
type Team = String
data Match = Match Team Int Team Int
Team is a synonym, not a new runtime wrapper. Match on the left is the type constructor, while the same spelling on the right is a data constructor in a different namespace. Its value-level type signature is Match :: Team -> Int -> Team -> Int -> Match.
Flatten the days, emit both participants of every match and remove repeated names:
teams :: [[Match]] -> [Team]
teams days = unique [t | Match a _ b _ <- concat days, t <- [a,b]]
  where
    unique []     = []
    unique (t:ts) = t : unique (filter (/= t) ts)
Every emitted name belongs to some match, and every participating team enters the intermediate list. At each recursive step, unique emits its first remaining name once and deletes precisely its later occurrences. Induction therefore proves both coverage and absence of duplicates. The output preserves first appearance; no particular team ordering was required. This simple list implementation can take quadratic time in the number of participant occurrences, which is permissible here; the question imposes no efficiency target.
Choose each team once using teams, then scan every match with that team as the reference perspective:
data Results = Results Team [(Int,Int)]

extract :: [[Match]] -> [Results]
extract days = [Results t (scores t) | t <- teams days]
  where
    games = concat days
    scores t = concatMap (contribution t) games
    contribution t (Match a ga b gb)
      | t == a    = [(ga,gb)]
      | t == b    = [(gb,ga)]
      | otherwise = []
In a valid match the teams are distinct. The first guard records the first team's goals-for and goals-against; the second reverses that perspective for the opponent. The common games binding preserves day/match order, although the result does not need a chronological ordering condition. Each team receives exactly one record because teams has no duplicates. The algorithm makes one scan per team; it deliberately prioritizes a transparent functional programming definition over an unrequested performance improvement.
Represent the ranking criteria by a tuple in decreasing priority:
type Weight = (Int,Int,Int)

weight :: Results -> Weight
weight (Results _ scores) =
  (sum (map points scores),
   sum [gf - ga | (gf,ga) <- scores],
   sum (map fst scores))
  where
    points (gf,ga)
      | gf > ga   = 3
      | gf == ga  = 1
      | otherwise = 0
The components are total points, total goal difference and total goals scored. The Haskell Ord class compares tuples in lexicographic order, so a greater first component dominates all later components; only ties reach the next criterion. Exactly equal triples remain tied because no further ranking criterion was specified. In the supplied fixture data the descending triples are , , , , , and , respectively for United, Athletic, City, Albion, Rovers, Corinthians and Thistle.

Articles by others on the same topic (0)

There are currently no matching articles.