Please fix your code indentation, as it is now it's painful to figure out what's supposed to be happening. The comments provide the corect suggestions to make it easy for you as well.
The characters for living and dead cells should be module-level constants. Makes them easily changeable and the code more readable:
LIVING_CELL = '#'
The frequency map is a good way to solve this. A nice trick to generate the frequency map is by creating a list of singleton maps and merging them all together:
wordFrequencyMap = Map.unionsWith (+) $ map (\x -> singleton x 1) $ normalizedWords str
I think this way is a bit more declarative which is what we aim for in Haskell.
You could simplify:
Using a Set
You are best to use a Set to reduce the complexity that comes with Array.includes.
Ignoring the sort. Your code has a complexity of \$O(n^2)\$ however using a set will reduce that to \$O(n)\$
Example of \$O(n^2)\$
dataA.filter(v => dataB.includes(v));
Example of same task with \$O(n)\$ complexity
set = new Set(dataB);
dataA.filter(v => set....
Avoid performing side-effects in the middle of a ternary expression. If you're not using the resulting value of the ternary operation, then you're using it wrong and should be using an ordinary if-then instead.
Also, be consistent with your usage of semicolons, and let/const.
const people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay',...
malloc() can return a null pointer
This code hides Undefined Behaviour:
char *file_contents = malloc(sizeof(char) * file_length); // dynamically allocated because of file size
fgets(file_contents, file_length, fp); // write the stream to the variable
We need to ensure that file_contents isn't a null pointer before we pass it into fgets.
Bug: failure to read entire file
fgets(file_contents, file_length, fp); only reads up to a line. Research fread().
Bug: insufficient allocation
fileCount does not account for the appended NULL.
// retArr = malloc(sizeof(*retArr) * fileCount);
retArr = malloc(sizeof *retArr * (fileCount + 1));
retArr[logFilePos + 1] = NULL;
Bug: 257 vs 256
int fgetc() ...
Pick a style
int get_file_char_count(FILE *f, char *filename);
int searchForKeyword(char *keyword, char *check_string);
You are mixing snake_case with camelCase names for your functions. I suggest that you stick with a single naming case for categories of names, so that all functions will use the same style. Pick one and use it everywhere.