Допустим, у меня есть следующая модель данных для отслеживания статистики бейсболистов, команд и тренеров:
data BBTeam = BBTeam { teamname :: String,
manager :: Coach,
players :: [BBPlayer] }
deriving (Show)
data Coach = Coach { coachname :: String,
favcussword :: String,
diet :: Diet }
deriving (Show)
data Diet = Diet { dietname :: String,
steaks :: Integer,
eggs :: Integer }
deriving (Show)
data BBPlayer = BBPlayer { playername :: String,
hits :: Integer,
era :: Double }
deriving (Show)
Теперь давайте скажем, что менеджеры, которые обычно являются фанатиками стейков, хотят есть еще больше стейков - поэтому мы должны иметь возможность увеличить содержание стейков в диете менеджера. Вот две возможные реализации этой функции:
1) При этом используется множество сопоставлений с образцом, и мне нужно правильно упорядочить все аргументы для всех конструкторов ... дважды. Похоже, что он не будет хорошо масштабироваться или будет очень удобен в обслуживании / читабельности.
addManagerSteak :: BBTeam -> BBTeam
addManagerSteak (BBTeam tname (Coach cname cuss (Diet dname oldsteaks oldeggs)) players) = BBTeam tname newcoach players
where
newcoach = Coach cname cuss (Diet dname (oldsteaks + 1) oldeggs)
2) При этом используются все методы доступа, предоставляемые синтаксисом записей Haskell, но он также уродлив и повторяется, и, я думаю, его трудно поддерживать и читать.
addManStk :: BBTeam -> BBTeam
addManStk team = newteam
where
newteam = BBTeam (teamname team) newmanager (players team)
newmanager = Coach (coachname oldcoach) (favcussword oldcoach) newdiet
oldcoach = manager team
newdiet = Diet (dietname olddiet) (oldsteaks + 1) (eggs olddiet)
olddiet = diet oldcoach
oldsteaks = steaks olddiet
Мой вопрос: один из них лучше другого или более предпочтителен в сообществе Haskell? Есть ли лучший способ сделать это (изменить значение глубоко внутри структуры данных, сохраняя при этом контекст)? Я не беспокоюсь об эффективности, просто элегантность кода / универсальность / ремонтопригодность.
Я заметил, что в Clojure есть что-то для этой проблемы (или аналогичной проблемы?): update-in
- так что я думаю, что я пытаюсь понять update-in
в контексте функционального программирования и Haskell и статической типизации .