да. Это может показаться слишком мощным, но использование библиотеки комбинатора синтаксического анализатора, такой как Parsec, позволит вам написать код аккуратно. Например.
import Text.ParserCombinators.Parsec
import Data.Maybe
monom, term :: Parser Term
operations :: [(Char,(Term -> Term -> Term))] -> Parser Term
int :: Parser Int
int = fmap read $ many1 digit
monom = do
coef <- int
string "x^"
power <- int
return $ Monom coef power
operations ops = do
a <- term
c <- choice . map (char . fst) $ ops
b <- term
return $ (fromJust $ lookup c ops) a b
term = do
char '('
x <- monom <|> (operations [('+', Addition), ('-', Subtraction), ('*', Multiplication), ('/', Division)])
char ')'
return x
term' = do
x <- term
eof
return x
readTerm :: String -> Term
readTerm string = case parse term' "" string of
Left err -> error . show $ err
Right term -> term
В качестве пояснения, monom
анализирует что-то вроде 2x^3
(без скобок), operations
берет список кортежей и анализирует term
, за которым следует один из символов операции, за которым следует еще один term
, а затем использует соответствующий конструктор данных для создания правильного экземпляра ( строку fromJust $ lookup c ops
).
Синтаксический анализатор term
анализирует либо monom
, либо одну из операций, заключенных в квадратные скобки. term'
анализирует всю строку (т. е. гарантирует, что анализатор работает до конца строки). readTerm
- это просто "более чистая" версия парсера.
Некоторые примеры:
> readTerm "(2x^3)"
Monom 2 3
> readTerm "((2x^3)+(2x^3))"
Addition (Monom 2 3) (Monom 2 3)
> readTerm "(((2x^3)+(2x^3))*(2x^3))"
Multiplication (Addition (Monom 2 3) (Monom 2 3)) (Monom 2 3)
Вышеупомянутая версия является очень простой версией, и ее можно легко расширить, чтобы (например) сделать термин coef
необязательным, чтобы x^2
анализировался как Monom 1 2
, или сделать термин power
необязательным, чтобы 2x
анализировался как Monom 2 1
. (Опция option
чрезвычайно полезна для этой конкретной модификации и добавляет всего 1 или 2 строки.)
(Примечание. Это может быть более эффективным и элегантным, написанным в аппликативном стиле, например.
import Control.Applicative
monom = Monom <$> int <* string "x^" <*> int
но это может стать немного громоздким при внесении изменений.)
person
huon
schedule
22.10.2012
deriving
Read and Show для вашего типа данных. Конечно, вы по-прежнему можете анализировать ввод (и отображать вывод) в формате, более удобном, чемAddition (Monom 1 3) (Monom 2 3)
. Так ли это? Если это так, вы можете использовать генератор синтаксических анализаторов или библиотеку синтаксического анализа, например Parsec. Но не на 100% понятно, что вы хотите сделать. - person Rafael Caetano   schedule 22.10.2012