简体   繁体   中英

Haskell implementation of rpn using foldr

I am trying to write a reverse Polish notation evaluator using foldr and this is what I have so far :

step :: [Int] -> String -> [Int] 
step (x * y):ys "*" = (x:y:ys)
step (x + y):ys "+" = (x:y:ys)
step (y - x):ys "-" = (x:y:ys)
step xs numberString = read numberString:xs

rpnRec ::[String] -> Int   
rpnRec [] = 1                                          
rpnRec = reverse .foldr step [] 

I have tried to resolve the error by swapping the positions of this : (x * y):ys and this (x:y:ys) but I keep getting this error:

Rpn.hs:14:7: error: Parse error in pattern: x * y
   |
14 | step (x * y):ys "*" = (x:y:ys)
   |       ^^^^^
Failed, no modules loaded.

any help would be appreciated on how to resolve this. Thank you

step :: [Int] -> String -> [Int]
step (x * y):ys "*" = (x:y:ys)
step (x + y):ys "+" = (x:y:ys)
step (y - x):ys "-" = (x:y:ys)
step xs numberString = read numberString:xs

Try saying

step (x:y:ys) "*" = (x * y) : ys

The same for the other operators. The last line of step looks OK.

There are some problems here. The first one is that you swap "input" and "output" in your step function. Indeed if you encounter a multiplication ( "*" ) you pop two items from the stack, and push the result of the multiplication on the stack. The step function should thus look like:

step :: [Int] -> String -> [Int] 
step  "*" = 
step  "+" = 
step  "-" = 
step xs numberString = read numberString:xs

The parenthesis for the (x:y:ys) are necessary here, since we use the same parameter: a list of Int s.

Furtermore you can not write foldr step [] and expect that it will yield an Int . The foldr will return the accumulator, and that is a list of Int s, hence foldr step [] somelist :: [Int] . You can use for example head to obtain the first element.

The type of the accumulator and the element should be swapped, we can make use of flip :: (a -> b -> c) -> b -> a -> c to flip the two parameters.

Finally you should reverse the list of strings, not the output, thus the function should look like:

rpnRec :: [String] -> Int
rpnRec =  . foldr ( step) [] . 
    where safeHead [] = 1
          safeHead (x:_) = x

For example:

Prelude> rpnRec ["2", "3", "*", "5", "+"]
11

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM