I'm not sure what you mean bu a callback function in the main loop - did you mean that 'main.c' file?
Anyway, the HAL tries to separate the code that it generates from the code that you write (mainly as it can over-write the code that it generated but wants to leave you code alone). When the ISR is triggered, it does whatever it needs to do to handle the interrupt (clear flags etc.) and then typically calls a function that is supplied by the HAL that is defined with the '__weak' attribute. Mostly that function will do nothing - in some cases there are special comment tags that let you add your own code that will not be over-written.
However the more usual approach is for you to write your own callback function that uses the same name as the HAL supplied one but does NOT have the 'weak' attribute. The linker knows about the 'weak' attribute and, if it sees another function with the same name but without the 'weak' attribute, it will connect all of the function references to that one; if there is only a 'weak' reference that that is the one that is used.
In this way, you can create your own callback function to do whatever you want within the context of the ISR, but if you don't, then the linker will not give you an 'undefined reference' error - it will quietly use the weak reference.
By the way, the PIC MCC uses a similar approach in some places. However, as you say, the PIC recommended approach is much more directly linked to the ISR code itself that you write.
Susan