.o в точности совпадает с объектными файлами C; файл .hi является «файлом интерфейса»; он содержит информацию о .o, которая понадобится GHC, если вы скомпилируете другие модули, чтобы иметь возможность ссылаться на этот файл .o (указанная информация не может быть сохранена в стандартном файле .o).
Можно сказать, что файл .hi является эквивалентом заголовочных файлов C (то есть с расширением .h), только они генерируются GHC из исходного источника на Haskell.
Таким образом, .hi используется, когда GHC компилирует другие модули, и .o используется, когда все модули объединяются для создания исполняемого файла.
Вы можете безопасно удалить файлы .hi и .o, как только вы успешно сгенерировали исполняемый файл (или сохраните их, если хотите внести небольшие изменения и быстро перестроить - это сэкономит время на ненужные перекомпиляции).