2016-06-07 6 views
0

Я программирую алгоритм восходящего восхождения в Haskell, но по неизвестной мне причине не работает. Я думаю, что Парсек состояние информация теряется в какой-то момент, но я даже не знаю, что является источником ошибки:приоритет восхождения в haskell: ошибка взаимной рекурсии parsec

module PrecedenceClimbing where 

import Text.Parsec 
import Text.Parsec.Char 

{- 
Algorithm 

compute_expr(min_prec): 
    result = compute_atom() 

    while cur token is a binary operator with precedence >= min_prec: 
    prec, assoc = precedence and associativity of current token 
    if assoc is left: 
     next_min_prec = prec + 1 
    else: 
     next_min_prec = prec 
    rhs = compute_expr(next_min_prec) 
    result = compute operator(result, rhs) 

    return result 
-} 

type Precedence = Int 
data Associativity = LeftAssoc 
        | RightAssoc 
        deriving (Eq, Show) 
data OperatorInfo = OPInfo Precedence Associativity (Int -> Int -> Int) 

mkOperator :: Char -> OperatorInfo 
mkOperator = \c -> case c of 
        '+' -> OPInfo 1 LeftAssoc (+) 
        '-' -> OPInfo 1 LeftAssoc (-) 
        '*' -> OPInfo 2 LeftAssoc (*) 
        '/' -> OPInfo 2 LeftAssoc div 
        '^' -> OPInfo 3 RightAssoc (^) 

getPrecedence :: OperatorInfo -> Precedence 
getPrecedence (OPInfo prec _ _) = prec 

getAssoc :: OperatorInfo -> Associativity 
getAssoc (OPInfo _ assoc _) = assoc 

getFun :: OperatorInfo -> (Int -> Int -> Int) 
getFun (OPInfo _ _ fun) = fun 

number :: Parsec String() Int 
number = do 
    spaces 
    fmap read $ many1 digit 

operator :: Parsec String() OperatorInfo 
operator = do 
    spaces 
    fmap mkOperator $ oneOf "+-*/^" 

computeAtom = do 
    spaces 
    number 

loop minPrec res = (do 
    oper <- operator 
    let prec = getPrecedence oper 
    if prec >= minPrec 
    then do 
    let assoc = getAssoc oper 
     next_min_prec = if assoc == LeftAssoc 
         then prec + 1 
         else prec 
    rhs <- computeExpr(next_min_prec) 
    loop minPrec $ getFun oper res rhs 
    else return res) <|> (return res) 

computeExpr :: Int -> Parsec String() Int 
computeExpr minPrec = (do 
    result <- computeAtom 
    loop minPrec result) <|> (computeAtom) 

getResult minPrec = parse (computeExpr minPrec) "" 

Моя программа по какой-то причине, только обработка первая операция или первый операнд в зависимости по делу, но не идти дальше сеанс

GHCI:

*PrecedenceClimbing> getResult 1 "46+10" 
Right 56 
*PrecedenceClimbing> getResult 1 "46+10+1" 
Right 56 
+0

Попробуйте закипать, что вплоть до [MCVE] и дать правильное описание проблем, которые вы получаете. – leftaroundabout

+0

сделано @leftaroundabout, теперь лучше объяснено и сокращено. – freinn

+0

Не могли бы вы прокомментировать ожидаемые значения для 'getResult 1 '46 + 10" 'и' getResult 1 "46 + 10 + 1" '? – hao

ответ

1

я не уверен точно, что случилось с вашим кодом, но я предложу эти комментарии:

(1) Эти утверждения не являются эквивалентными:

Generic Imperative: rhs = compute_expr(next_min_prec) 

Haskell:   rhs <- computeExpr(next_min_prec) 

Императив вызов compute_expr будет всегда возвращение. Вызов Haskell может завершиться неудачно, и в этом случае материал, следующий за вызовом, никогда не произойдет.

(2) Вы действительно работаете против сильных сторон Parsec, пытаясь разобрать маркеры по одному в последовательности. Для того, чтобы увидеть "Парсек путь" в общем разборе выражений с операторами различных старшинства и ассоциативности, посмотрите на:

Update

Я ve разместил решение к http://lpaste.net/165651

+0

Я просто пытаюсь использовать этот алгоритм, но я поддержал ваш ответ, потому что я думаю, что это полезно для моей будущей работы и для читателей этого вопрос. – freinn

+0

Ответ обновлен. – ErikR