So, I have been thinking (shocking, I know). Consider:
data Country = Country {name1 :: String, company :: Company} deriving Show
data Company = Company {name2 :: String, boss :: Employee, car :: Car} deriving Show
data Employee = Employee {name3 :: String, age :: Integer, empCar :: Car} deriving Show
data Car = Car {name4 :: String} deriving Show
(Yes, I’m not using duplicated fields because that’s a different discussion.) When working with records, getting the values is never a real pain point. Not even for nested records. Using the named field functions elegantly compose to extract what you want.
f :: Country -> Integer
f = age . boss . company
Updating a deeply nested value is the issue. You have to get to the final record, apply the changes, then recursively apply changes until reaching the first record. It gets verbose fast. It looks even worse when you want to do multiple changes on other deeply nested records.
g :: Country -> Integer -> Country
g r i = let x1 = company r
x2 = boss x1
in r { company = x1 { boss = x2 { age = i } } }
You can change it a bit:
g :: Country -> Integer -> Country
g r i = r { company = (company r) { boss = (boss (company r)) { age = i } } }
I looked at this at thought: “can you introduce something to desugarize into this?”.
I thought of something like this:
r { company ~= { boss ~= { age = i } } }
The ~= should grab the expression to the left of his parent { and replace himself with the function to his left and a =. That way the previous expression would be equivalent to:
r { company = (company (r)) { boss = (boss (company (r))) { age = i } } }
Another equivalence:
r { company = (company (r)) { boss = (boss (company (r)) { age = i }
, car = (car (company (r)) { name4 = "new" }
, name2 = "cmp" }
, name1 = "ccc" }
-- is this
r { company ~= { boss ~= { age = i }
, car ~= { name4 = "new" }
, name2 = "cmp" }
, name1 = "ccc" }
At this point I noticed the commas and the blocks, and thought of rewriting this:
r { company ~= { boss ~= { age = i }
, car ~= { name4 = "new" }
, name2 = "cmp" }
, name1 = "ccc" }
into this:
r do
company do
boss do
age = i
car do
name4 = "new"
name2 = "cmp"
name1 = "ccc"
My first question is: is this even possible?
My second question is: am I insane?
What do you think?