В общем разобрался:
func3 означает, что при передаче вторым аргументом 0 - надо всегда возвращать первый аргумент без изменений.
А при передаче первым аргументом пустого списка - всегда пустой список.
В остальных случаях -
Если func1 xs < n (func1 считает длину списка), то вернуть xs, иначе (какая-то сложная штука)
В func2 при помощи @ мы просто вытаскиваем первый элемент списка в _ (спасибо mikeyuriev за поправку), а хвоста списка - в xs'
А дальше идёт рекурсивный вызов.
В результате func2 отбросит n первых элементов списка
func1 - рекурскивно считает длину списка
func2 - отбрасывает первые n элементов списка
func3 - как раз чередует элементы списка.
А теперь про "сложную штуку"
n `take` xs ++ [y] ++ func3 (drop n xs) n y
take берёт первые n элементов списка (тут используется инфиксная форма, по тому и страшно)
++ - конкатенирует два списка
drop - то же самое, что и func2
Таким образом мы берём n первых элементов списка, приклеиваем разделитель, и повторяем то же самое с оставшимся хвостом, пока список не кончится.
По этой причине при пустом исходном списке нет и смысла чередовать, как и при нулевом периоде чередования.
PS: решение красивое и элегантное, мне нравится.