Solution (source code)

= Solution

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.