Во-первых, заменим
splitOn " "
на
words
, который съест все пробелы. Далее,
concat $ map ...
- это то же, что и
concatMap ...
. Рассмотрим
sepBr
. Он берёт строку без пробелов и делит её на куски, если там есть операторы, числа или скобки. Если строка уже пустая, результат - пустой список. Если строка непустая, то возможны варианты. Если первый её символ - какая-то скобка, отделяем эту скобку, а остальное делим опять при помощи
sepBr
. Иначе делаем так: разделим строку, чтобы сначала шли только цифры:
span isDigit
и посмотрим, что получилось. Если цифры есть - отделяем их, а остальное опять делим
sepBr
. Если цифр нет, то просто отделяем первый символ. Вот, что получилось:
sep ∷ String → [String]
sep = concatMap sepBr . words where
sepBr ∷ String → [String]
sepBr "" = [] -- нечего делить
sepBr s'@(x:xs)
| x `elem` "()" = [x] : sepBr xs -- скобка
| otherwise = case span isDigit s' of -- возьмём цифры
("", t:tl) → [t] : sepBr tl -- нет цифр, берём первый символ остатка
(n, tl) → n : sepBr tl -- есть цифры, их отдельно
По поводу вашего второго варианта.
if word == [] then [] else head word
- т.е.
a
либо пустой список, либо символ, типы не совпадают. Но в вашем случае
word
не может быть пустым, ведь выше уже был паттерн
sepBr ""
, так что можно просто оставить
a = head word
Далее, что такое
ab
? Это
[a] ++ b
, т.е.
[head word] ++ init (tail word)
, т.е. это то же, что и просто
init word
. Аналогично
bc = tail word
. Вместо того, чтобы брать отдельно
head
и отдельно
tail
, можно воспользоваться паттерн-матчингом и записать
(a : bc) = word
.
С учётом этого ваш вариант переписывается в
sep2 ∷ String → [String]
sep2 = concatMap sepBr . words where
sepBr ∷ String → [String]
sepBr "" = []
sepBr " " = []
sepBr word
| a `elem` brackets = [[a]] ++ sepBr bc
| c `elem` brackets = sepBr ab ++ [[c]]
| otherwise = ([a : bc])
where
(a : bc) = word
c = last word
ab = init word
brackets = ['(', ')']
И он вполне работает.