Haskell supports structs with named fields out of the box in the form of records.
data Foo = Foo { attr :: Integer, attr2 :: Integer }
printSomeNumbers = do
let x = Foo { attr = 3, attr2 = 4 }
print (attr x)
let y = x { attr = 7 }
print (attr x)
It's true that the formatting is different, but given the rest of the language that's not really a problem. What is a problem is how ugly
nested record updates are:
data Bar = Bar { attr3 :: Integer, foo :: Foo }
setTheThing x i = x { foo = (foo x) { attr = i }}
That's... not great, is it? And as you get deeper it gets worse, and it can actually get less efficient to as you keep diving down through structures to grab the pieces you need to reconstruct the unchanged parts of your new copy of the record.
So it's not about "x.attr", but "x.attr.field = 7" and friends.