Необходимо изучить Hashlife, окончательная оптимизация. Это использует дерево квадрантов подход это упомянутый skinp.
проблема в том, что вы перепутали 2 функции:
zeez / 2 и zeez / 3
Если вы завершите функцию zeez / 3, завершив ее точкой, не точка с запятой, которую он должен скомпилировать:
zeez(true, M, N) ->
io:format("~p~n", [zeez(space, N-M)] ), % line 16
zeez(M rem N =:= 0, M + 1 , N ); <-- should end with .
Сообщение об ошибке означает: «Эй, я в zeez / 3, а вы добавили предложение с двумя арностями, wtf?»
Вы пытаетесь определить две функции, первую с 3 параметрами (zeez / 3) и другую с 2 параметрами (zeez / 2). Ошибка несоответствия заголовка возникает из-за того, что функция zeez / 3 в предыдущей строке должна заканчиваться символом '.'.
Т.е. поскольку вы завершили предыдущую функцию zeez / 3 символом ';', ожидается, что следующее объявление будет другим совпадением для zeez / 3:
zeez(true, M, N) ->
io:format("~p~n", [zeez(space, N-M)] ), % line 16
zeez(M rem N =:= 0, M + 1 , N ).
zeez(space, M) ->
io:format("~p~n", ["-" ++ zeez(space, M-1)] );
Также следует отметить, что компилятор выдаст вам предупреждения о «... предыдущее предложение в строке xxx всегда совпадает» из-за порядка zees (пробел, 0) и zeez (пробел, M). Вы должны поставить zees (пробел, 0) перед zeez (пробел, M), потому что это более конкретно.