"(+ 12 (* 3 4))"
на список лексем вида ["(", "+", "12", "(", "*", "3", "4", ")", ")"]
import Data.Char
import Data.List.Split
import Data.Maybe
import Text.Read
sep :: String -> [String]
sep s = concat $ map sepBr (splitOn " " s) where
sepBr :: String -> [String]
sepBr "" = []
sepBr " " = []
sepBr (x:xs)
| x `elem` ['(', ')'] = ([x] : sepBr xs)
| otherwise = ([x] : [xs])
["(","+","","1","2","(","*","","3","","4","))"]
. Пустые строки можно было бы вычистить с помощью filter, а вот что делать со склеившимися скобочками и расклеившимся числом не знаю.import Data.Char
import Data.List.Split
import Data.Maybe
import Text.Read
sep :: String -> [String]
sep s = concat $ map sepBr (splitOn " " s) 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 = if word == [] then [] else head word
b = if word == [] then [] else init $ tail word
c = if word == [] then [] else last word
ab = [a] ++ b
bc = b ++ [c]
brackets = ['(', ')']
src/Main.hs@13:20-13:28 Couldn't match type Char with [t1]
Expected type: [[t1]]
Actual type: [Char] …
src/Main.hs@13:33-13:34 Couldn't match expected type Char with actual type [t2] …
src/Main.hs@14:20-14:28 Couldn't match type Char with [t3]
Expected type: [[t3]]
Actual type: [Char] …
src/Main.hs@14:37-14:39 Couldn't match type [t4] with Char
Expected type: String
Actual type: [[t4]] …
src/Main.hs@14:45-14:46 Couldn't match expected type Char with actual type [t5] …
src/Main.hs@15:33-15:34 Couldn't match expected type Char with actual type [t6] …
src/Main.hs@16:58-16:62 Couldn't match type Char with [t]
Expected type: [[t]]
Actual type: String
Relevant bindings include
a :: [t]
(bound at /home/app/isolation-runner-work/projects/119295/session.207/src/src/Main.hs:16:15) …
src/Main.hs@18:58-18:62 Couldn't match type Char with [t]
Expected type: [[t]]
Actual type: String
Relevant bindings include
c :: [t]
(bound at /home/app/isolation-runner-work/projects/119295/session.207/src/src/Main.hs:18:15) …
src/Main.hs@19:33-19:34 Couldn't match type Char with [t]
Expected type: [[t]]
Actual type: [Char]
Relevant bindings include
ab :: [[t]]
(bound at /home/app/isolation-runner-work/projects/119295/session.207/src/src/Main.hs:19:15) …
src/Main.hs@20:32-20:33 Couldn't match expected type Char with actual type [t0] …
[[t]]
, если тип функции last :: [a] -> a
. То же и с остальными функциями, почему a
не может быть символом (Char)? 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 = ['(', ')']
data Token = NumToken Double | OpToken Operator | LeftParenToken | RightParenToken
data Operator = Plus | Minus | Mult | Div
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]
number :: Char -> String -> [Token]
number c cs =
-- разбиваем строку на цифровые символы, идущие друг за другом,
-- и на остаток строки при помощи функции span
let (digits,rest) = span isDigit cs
-- сразу переводим полученные цифровые символы в число
-- при помощи функции read и токенизируем остаток строки
in NumToken (read $ c:digits) : strToToken rest