Причина, по которой это не компилируется, заключается в том, что Haskell видит ваше последнее предложение как:
split c st = takeWhile (/=c) st : split c tail ((dropWhile (/=c) st))
Таким образом, он думает, что вы применили три параметра к split
: c
, tail
и ((dropWhile (/=c) st))
.Здесь следует использовать скобки, например:
split c st = takeWhile (/=c) st : split c (tail (dropWhile (/=c) st))
Но это не решит проблему полностью.Например, если мы попытаемся запустить ваш тестовый сценарий, мы увидим:
Prelude> split '#' "foo##goo"
["foo","","goo"*** Exception: Prelude.tail: empty list
tail :: [a] -> [a]
- это «неполная» функция.Для пустого списка tail
будет ошибка.Действительно:
Prelude> tail []
*** Exception: Prelude.tail: empty list
В конечном итоге в списке не будет символов, а затем tail
вызовет ошибку.Мы можем использовать span :: (a -> Bool) -> [a] -> ([a], [a])
здесь и использовать сопоставление с образцом, чтобы определить, есть ли еще какой-то элемент, который необходимо обработать, например:
split :: Eq a => a -> [a] -> [[a]]
split _ [] = [[]]
split c txt = pf : rst
where rst | (_:sf1) <- sf = split c sf1
| otherwise = []
(pf,sf) = span (c /=) txt
Здесь span (c /=) txt
, таким образом, разделит непустой список txt
на две части pf
( prefix ) - самый длинный префикс элементов, которые не равны c
.sf
(суффикс) - остальные элементы.
Независимо от того, пусто sf
или нет, мы передаем префикс pf
.Затем мы проверяем суффикс.Мы знаем, что либо sf
пусто (мы достигли конца списка), либо что первый элемент sf
равен c
.Таким образом, мы используем pattern guard , чтобы проверить, соответствует ли это шаблону (_:sf1)
.Это происходит, если sf
не пусто.В этом случае мы связываем sf1
с хвостом sf
, и мы повторяем на хвосте.Если sf1
пусто, мы можем остановиться и, таким образом, вернуть []
.
Например:
Prelude> split '#' "foo##goo"
["foo","","goo"]
Prelude> split '#' "#"
["",""]