How to simplify the record syntax with pattern matching?
First, when you are not using fields in a record, you don't have to use _ to mark that they should be ignored;  you only need to include the fields in the pattern that you are actually using.

Second, it is possible to update a couple of fields in a record without respecifying the whole thing from scratch.  If x is the name of the old record and you want to set the field a to 42 and b to 24, then the expression x { a = 42, b = 24 } is equal to the record x with a set to 42 and b set to 24.

Putting these ideas together, autoAttack could be rewritten like so:

autoAttack :: Actor -&gt; Actor -&gt; Actor
autoAttack actor@(Actor {stats = stats@(StatsSystem {physicalDamage = p, health = h}})) =
    actor {stats = stats { health = h - p } }


Where we have used the syntax actor@(Actor ..) to bind the Actor to the name actor, which is a useful pattern for when you want to both pattern match on an argument and also have access to its value.



Just to be clear, it is worth mentioning that, because data is immutable, changing a couple of fields involves making a full copy of the data structure.  (Thanks to Daniel Wagner for bringing this up).