Вопрос: Как рекурсивно распарсить скобки?

Лучший ответ:
Во-первых, заменим 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 = ['(', ')']
И он вполне работает.

Худший ответ:
Вы, почему-то, не используете одну из самых мощных фич Хаскелла - типы. Программа гораздо легче пишется, когда вы её сначала написали на уровне типов. Функции после этого пишутся гораздо легче. 
Переходя к вашей задаче: я бы разделил её на два этапа.
1. Лексический разбор строки на список токенов. 
2. Парсинг списка токенов в выражение. 
Какие у вас могут быть токены? Числа, операторы, левая и правая скобки. Вот их и кодируйте в типе Token: data Token = NumToken Double | OpToken Operator | LeftParenToken | RightParenToken

data Operator = Plus | Minus | Mult | Div
В типе Token конструктору данных NumToken я передал Double, т.к. если у вас будет деление, с Int или Integer вы не сможете его произвести без дополнительной конвертации. 
Дальше вы должны превратить вашу строку в список токенов. Это отлично делается рекурсией: strToToken :: String -> [Token]
strToToken [] = []
strToToken (c:cs)
    -- Токенизируем голову списка и вызываем токенизацию на его хвосте
    | c == '(' = LeftParenToken : strToToken cs
    | c == ')' = RightParenToken : strToToken cs
    -- Если встречается пробел - откидываем его и токенизируем строку дальше
    | isSpace c = strToToken cs
    -- если встречается число, вызываем функцию-хелпер number
    | isDigit c = number c cs
    -- не забываем о случаях, когда строку не удалось распарсить полностью
    | otherwise = error $ "Не могу распарсить " ++ [c]
Функция strToToken и вспомогательная функция number являются взаимно рекурсивными. Из функции strToToken мы вызываем функцию number, а из функции number мы вызываем функцию strToToken: number :: Char -> String -> [Token]
number c cs =
    -- разбиваем строку на цифровые символы, идущие друг за другом, 
    -- и на остаток строки при помощи функции span
    let (digits,rest) = span isDigit cs
    -- сразу переводим полученные цифровые символы в число 
    -- при помощи функции read и токенизируем остаток строки
    in NumToken (read $ c:digits) : strToToken rest
Вот вы и сконвертировали строку в список лексем. Следующая задача - парсинг лексем в выражения. Советую точно так же создать тип, содержащий все возможные выражения. Подсказка: этот тип у вас получится рекурсивным, т.к. выражение может состоять из нескольких выражений, разделённых операторами.