Хаскелл рекурсивная проблема, крошечный парсер. Отрицание Expr и пусть выражений - PullRequest
3 голосов
/ 06 октября 2009
data Expr =  Var Char | Tall Int | Sum Expr Expr | Mult Expr Expr | Neg Expr | Let Expr Expr Expr
    deriving(Eq, Show) 

parseExpr :: String -> (Expr, String)

parseExpr ('*':'(':s) = (Mult x y, s'')
    where (x,',':s') = parseExpr s
          (y,')':s'') = parseExpr s'
parseExpr ('+':'(':s) = (Sum x y, s'')
    where (x,',':s') = parseExpr s
          (y,')':s'') = parseExpr s'
parseExpr (x : xs) | isDigit x = (Tall (digitToInt x), xs)
parseExpr (x:s) = (Var x,s) 
    where   x >= 'A' = True
        x <= 'Z' = True 

Моему парсеру не хватает двух вещей до его завершения. Начиная с типа данных выше его не хватает "Neg Expr" и пусть "Expr Expr Expr". Первая часть будет выглядеть примерно так:

parseExpr('-' 
parseExpr('l':'e':'t':x:'b':'e 

Как и в типе данных, выражения Let начинаются с let и принимают три Expr. Я не знаю, как написать эти последние функции. Любая помощь будет очень цениться.

Я задал еще один вопрос здесь на SO, и здесь - ссылка на этот вопрос


Вот пример:

parseProg "let X be 4 in let Y be *(2 , X) in let Z be +(Y , X) in
+(+(X , Y) , Z)"
Let (Var 'X') (Tall 4) (Let (Var 'Y') (Mult (Tall 2) (Var 'X')) (Let
(Var 'Z') (Sum (Var 'Y') (Var 'X')) (Sum (Sum (Var 'X') (Var 'Y')) (Var
'Z'))))

1 Ответ

1 голос
/ 06 октября 2009

Основная стратегия для этих частей выражения будет такой же, как и для других операций, только вам не нужно анализировать два подвыражения, а только один или три. Для let это будет выглядеть так:

parseExpr ('l':'e':'t':s) = (Let x y z, s3)
    where (x, 'b':'e':s1) = parseExpr s
          (y, 'i':'n':s2) = parseExpr s1
          (z, s3)         = parseExpr s2

Если строка начинается с букв l, e, t, возьмите оставшуюся строку (s) и попытайтесь проанализировать выражение из нее. Это приводит к выражению (x) и оставшейся строке. Мы ожидаем, что эта оставшаяся строка начинается с букв b, e. Поскольку за этим должно следовать другое выражение, мы передаем оставшуюся часть этой строки (s2) снова parseExpr для анализа другого выражения. И так далее.

Единственная проблема с этим заключается в том, что мы не учитываем пробелы, которые могут отделить эти ключевые слова, такие как «let» и «be», от окружающих выражений. Простым решением было бы потребовать ровно один пробел до / после этих ключевых слов и изменить шаблоны в parseExpr, чтобы явно включить их, например:

    where (x, ' ':'b':'e':' ':s1) = parseExpr s

Более гибким было бы добавить функцию dropSpaces :: String -> String, которая удаляет начальные пробелы и вызывается в соответствующих местах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...