Infix to postfix notation in Haskell (Shunting-yard algorithm)












3














I've written an infix to postfix converter in Haskell using the Shunting-yard algorithm. Example of how it works:



$ ./in2post 
2 + 2
2 2 +
$ ./in2post
1 + 2 * 3
1 2 3 * +
$ ./in2post
(5 - 4) * 3+1005/(12-6*(12 -8) )
5 4 - 3 * 1005 12 6 12 8 - * - / +
$ ./in2post
(2 + 45
2 45 + ERROR


And the source code:



Main.hs



module Main (main) where

import System.IO
import InToPost

main :: IO ()
main = do
line <- getLine
let tokens = tokenise line
newexpr = shuntYard tokens
putStrLn $ untokenise newexpr


InToPost.hs



module InToPost
( Token(TNum, TOp)
, Operator
, splitTok
, tokenise
, untokenise
, shuntYard
) where

import Data.Char (isSpace, isDigit)
import Data.List (groupBy)

data Token = TNum Int
| TOp Operator
deriving (Show)
data Operator = Add
| Sub
| Mult
| Div
| LBrace
| RBrace
deriving (Show, Eq)

splitTok :: String -> [String]
splitTok = groupBy (x y -> isDigit x && isDigit y) . filter (not . isSpace)

str2tok :: String -> Either String Token
str2tok tkn@(c:_)
| isDigit c = Right $ TNum $ read tkn
| otherwise = case tkn of
"+" -> Right $ TOp Add
"-" -> Right $ TOp Sub
"*" -> Right $ TOp Mult
"/" -> Right $ TOp Div
"(" -> Right $ TOp LBrace
")" -> Right $ TOp RBrace
_ -> Left $ "No such operator: "" ++ tkn ++ """

tok2str :: Token -> String
tok2str (TNum t) = show t
tok2str (TOp t) = case t of
Add -> "+"
Sub -> "-"
Mult -> "*"
Div -> "/"
_ -> "ERROR"

precedence :: Operator -> Int
precedence Add = 1
precedence Sub = 1
precedence Mult = 2
precedence Div = 2
precedence LBrace = 3
precedence RBrace = 3

-- shuntYard (Operator stack) (Token Queue) (Token Buffer) = new Token Queue
shuntYard :: [Operator] -> [Token] -> [Either String Token] -> Either String [Token]
shuntYard _ _ (Left s:_) = Left s
shuntYard stack queue = Right $ queue ++ map TOp stack
shuntYard stack queue (Right (TNum t):ts) = shuntYard stack (queue ++ [TNum t]) ts
shuntYard stack queue (Right (TOp t):ts) =
shuntYard ustack uqueue ts
where
(ustack, uqueue) = case t of
LBrace -> (t : stack, queue)
RBrace -> (stail srest, queue ++ map TOp sstart)
_ -> (t : ssend, queue ++ map TOp ssops)
(sstart, srest) = break (==LBrace) stack
currprec = precedence t
(ssops, ssend) = span (op -> precedence op > currprec && op /= LBrace) stack
stail :: [a] -> [a]
stail (x:xs) = xs
stail =

tokenise :: String -> [Either String Token]
tokenise = map str2tok . splitTok

untokenise :: Either String [Token] -> String
untokenise (Left s) = s
untokenise (Right ts) = unwords . map tok2str $ ts


Please tell me, what are my bad practices here? For example, the use of Either felt really awkward and I'm sure it can be done better. Also, the case expression in str2tok is quite ugly.










share|improve this question





























    3














    I've written an infix to postfix converter in Haskell using the Shunting-yard algorithm. Example of how it works:



    $ ./in2post 
    2 + 2
    2 2 +
    $ ./in2post
    1 + 2 * 3
    1 2 3 * +
    $ ./in2post
    (5 - 4) * 3+1005/(12-6*(12 -8) )
    5 4 - 3 * 1005 12 6 12 8 - * - / +
    $ ./in2post
    (2 + 45
    2 45 + ERROR


    And the source code:



    Main.hs



    module Main (main) where

    import System.IO
    import InToPost

    main :: IO ()
    main = do
    line <- getLine
    let tokens = tokenise line
    newexpr = shuntYard tokens
    putStrLn $ untokenise newexpr


    InToPost.hs



    module InToPost
    ( Token(TNum, TOp)
    , Operator
    , splitTok
    , tokenise
    , untokenise
    , shuntYard
    ) where

    import Data.Char (isSpace, isDigit)
    import Data.List (groupBy)

    data Token = TNum Int
    | TOp Operator
    deriving (Show)
    data Operator = Add
    | Sub
    | Mult
    | Div
    | LBrace
    | RBrace
    deriving (Show, Eq)

    splitTok :: String -> [String]
    splitTok = groupBy (x y -> isDigit x && isDigit y) . filter (not . isSpace)

    str2tok :: String -> Either String Token
    str2tok tkn@(c:_)
    | isDigit c = Right $ TNum $ read tkn
    | otherwise = case tkn of
    "+" -> Right $ TOp Add
    "-" -> Right $ TOp Sub
    "*" -> Right $ TOp Mult
    "/" -> Right $ TOp Div
    "(" -> Right $ TOp LBrace
    ")" -> Right $ TOp RBrace
    _ -> Left $ "No such operator: "" ++ tkn ++ """

    tok2str :: Token -> String
    tok2str (TNum t) = show t
    tok2str (TOp t) = case t of
    Add -> "+"
    Sub -> "-"
    Mult -> "*"
    Div -> "/"
    _ -> "ERROR"

    precedence :: Operator -> Int
    precedence Add = 1
    precedence Sub = 1
    precedence Mult = 2
    precedence Div = 2
    precedence LBrace = 3
    precedence RBrace = 3

    -- shuntYard (Operator stack) (Token Queue) (Token Buffer) = new Token Queue
    shuntYard :: [Operator] -> [Token] -> [Either String Token] -> Either String [Token]
    shuntYard _ _ (Left s:_) = Left s
    shuntYard stack queue = Right $ queue ++ map TOp stack
    shuntYard stack queue (Right (TNum t):ts) = shuntYard stack (queue ++ [TNum t]) ts
    shuntYard stack queue (Right (TOp t):ts) =
    shuntYard ustack uqueue ts
    where
    (ustack, uqueue) = case t of
    LBrace -> (t : stack, queue)
    RBrace -> (stail srest, queue ++ map TOp sstart)
    _ -> (t : ssend, queue ++ map TOp ssops)
    (sstart, srest) = break (==LBrace) stack
    currprec = precedence t
    (ssops, ssend) = span (op -> precedence op > currprec && op /= LBrace) stack
    stail :: [a] -> [a]
    stail (x:xs) = xs
    stail =

    tokenise :: String -> [Either String Token]
    tokenise = map str2tok . splitTok

    untokenise :: Either String [Token] -> String
    untokenise (Left s) = s
    untokenise (Right ts) = unwords . map tok2str $ ts


    Please tell me, what are my bad practices here? For example, the use of Either felt really awkward and I'm sure it can be done better. Also, the case expression in str2tok is quite ugly.










    share|improve this question



























      3












      3








      3







      I've written an infix to postfix converter in Haskell using the Shunting-yard algorithm. Example of how it works:



      $ ./in2post 
      2 + 2
      2 2 +
      $ ./in2post
      1 + 2 * 3
      1 2 3 * +
      $ ./in2post
      (5 - 4) * 3+1005/(12-6*(12 -8) )
      5 4 - 3 * 1005 12 6 12 8 - * - / +
      $ ./in2post
      (2 + 45
      2 45 + ERROR


      And the source code:



      Main.hs



      module Main (main) where

      import System.IO
      import InToPost

      main :: IO ()
      main = do
      line <- getLine
      let tokens = tokenise line
      newexpr = shuntYard tokens
      putStrLn $ untokenise newexpr


      InToPost.hs



      module InToPost
      ( Token(TNum, TOp)
      , Operator
      , splitTok
      , tokenise
      , untokenise
      , shuntYard
      ) where

      import Data.Char (isSpace, isDigit)
      import Data.List (groupBy)

      data Token = TNum Int
      | TOp Operator
      deriving (Show)
      data Operator = Add
      | Sub
      | Mult
      | Div
      | LBrace
      | RBrace
      deriving (Show, Eq)

      splitTok :: String -> [String]
      splitTok = groupBy (x y -> isDigit x && isDigit y) . filter (not . isSpace)

      str2tok :: String -> Either String Token
      str2tok tkn@(c:_)
      | isDigit c = Right $ TNum $ read tkn
      | otherwise = case tkn of
      "+" -> Right $ TOp Add
      "-" -> Right $ TOp Sub
      "*" -> Right $ TOp Mult
      "/" -> Right $ TOp Div
      "(" -> Right $ TOp LBrace
      ")" -> Right $ TOp RBrace
      _ -> Left $ "No such operator: "" ++ tkn ++ """

      tok2str :: Token -> String
      tok2str (TNum t) = show t
      tok2str (TOp t) = case t of
      Add -> "+"
      Sub -> "-"
      Mult -> "*"
      Div -> "/"
      _ -> "ERROR"

      precedence :: Operator -> Int
      precedence Add = 1
      precedence Sub = 1
      precedence Mult = 2
      precedence Div = 2
      precedence LBrace = 3
      precedence RBrace = 3

      -- shuntYard (Operator stack) (Token Queue) (Token Buffer) = new Token Queue
      shuntYard :: [Operator] -> [Token] -> [Either String Token] -> Either String [Token]
      shuntYard _ _ (Left s:_) = Left s
      shuntYard stack queue = Right $ queue ++ map TOp stack
      shuntYard stack queue (Right (TNum t):ts) = shuntYard stack (queue ++ [TNum t]) ts
      shuntYard stack queue (Right (TOp t):ts) =
      shuntYard ustack uqueue ts
      where
      (ustack, uqueue) = case t of
      LBrace -> (t : stack, queue)
      RBrace -> (stail srest, queue ++ map TOp sstart)
      _ -> (t : ssend, queue ++ map TOp ssops)
      (sstart, srest) = break (==LBrace) stack
      currprec = precedence t
      (ssops, ssend) = span (op -> precedence op > currprec && op /= LBrace) stack
      stail :: [a] -> [a]
      stail (x:xs) = xs
      stail =

      tokenise :: String -> [Either String Token]
      tokenise = map str2tok . splitTok

      untokenise :: Either String [Token] -> String
      untokenise (Left s) = s
      untokenise (Right ts) = unwords . map tok2str $ ts


      Please tell me, what are my bad practices here? For example, the use of Either felt really awkward and I'm sure it can be done better. Also, the case expression in str2tok is quite ugly.










      share|improve this question















      I've written an infix to postfix converter in Haskell using the Shunting-yard algorithm. Example of how it works:



      $ ./in2post 
      2 + 2
      2 2 +
      $ ./in2post
      1 + 2 * 3
      1 2 3 * +
      $ ./in2post
      (5 - 4) * 3+1005/(12-6*(12 -8) )
      5 4 - 3 * 1005 12 6 12 8 - * - / +
      $ ./in2post
      (2 + 45
      2 45 + ERROR


      And the source code:



      Main.hs



      module Main (main) where

      import System.IO
      import InToPost

      main :: IO ()
      main = do
      line <- getLine
      let tokens = tokenise line
      newexpr = shuntYard tokens
      putStrLn $ untokenise newexpr


      InToPost.hs



      module InToPost
      ( Token(TNum, TOp)
      , Operator
      , splitTok
      , tokenise
      , untokenise
      , shuntYard
      ) where

      import Data.Char (isSpace, isDigit)
      import Data.List (groupBy)

      data Token = TNum Int
      | TOp Operator
      deriving (Show)
      data Operator = Add
      | Sub
      | Mult
      | Div
      | LBrace
      | RBrace
      deriving (Show, Eq)

      splitTok :: String -> [String]
      splitTok = groupBy (x y -> isDigit x && isDigit y) . filter (not . isSpace)

      str2tok :: String -> Either String Token
      str2tok tkn@(c:_)
      | isDigit c = Right $ TNum $ read tkn
      | otherwise = case tkn of
      "+" -> Right $ TOp Add
      "-" -> Right $ TOp Sub
      "*" -> Right $ TOp Mult
      "/" -> Right $ TOp Div
      "(" -> Right $ TOp LBrace
      ")" -> Right $ TOp RBrace
      _ -> Left $ "No such operator: "" ++ tkn ++ """

      tok2str :: Token -> String
      tok2str (TNum t) = show t
      tok2str (TOp t) = case t of
      Add -> "+"
      Sub -> "-"
      Mult -> "*"
      Div -> "/"
      _ -> "ERROR"

      precedence :: Operator -> Int
      precedence Add = 1
      precedence Sub = 1
      precedence Mult = 2
      precedence Div = 2
      precedence LBrace = 3
      precedence RBrace = 3

      -- shuntYard (Operator stack) (Token Queue) (Token Buffer) = new Token Queue
      shuntYard :: [Operator] -> [Token] -> [Either String Token] -> Either String [Token]
      shuntYard _ _ (Left s:_) = Left s
      shuntYard stack queue = Right $ queue ++ map TOp stack
      shuntYard stack queue (Right (TNum t):ts) = shuntYard stack (queue ++ [TNum t]) ts
      shuntYard stack queue (Right (TOp t):ts) =
      shuntYard ustack uqueue ts
      where
      (ustack, uqueue) = case t of
      LBrace -> (t : stack, queue)
      RBrace -> (stail srest, queue ++ map TOp sstart)
      _ -> (t : ssend, queue ++ map TOp ssops)
      (sstart, srest) = break (==LBrace) stack
      currprec = precedence t
      (ssops, ssend) = span (op -> precedence op > currprec && op /= LBrace) stack
      stail :: [a] -> [a]
      stail (x:xs) = xs
      stail =

      tokenise :: String -> [Either String Token]
      tokenise = map str2tok . splitTok

      untokenise :: Either String [Token] -> String
      untokenise (Left s) = s
      untokenise (Right ts) = unwords . map tok2str $ ts


      Please tell me, what are my bad practices here? For example, the use of Either felt really awkward and I'm sure it can be done better. Also, the case expression in str2tok is quite ugly.







      algorithm parsing haskell math-expression-eval






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 2 days ago







      atmostmediocre

















      asked 2 days ago









      atmostmediocreatmostmediocre

      454




      454






















          1 Answer
          1






          active

          oldest

          votes


















          1














          main :: IO ()
          main = do
          line <- getLine
          putStrLn $ case traverse str2tok $ splitTok line of
          Left s -> s
          Right ts -> unwords $ map tok2str $ shuntYard ts

          -- shuntYard (Token Buffer) = new Token Queue
          shuntYard :: [Token] -> [Token]
          shuntYard ts = concat queue ++ stack where
          (queue, stack) = (`runState` ) $ for ts $ state . case
          TNum t -> ([TNum t],)
          TOp LBrace -> (,) . (LBrace :)
          TOp RBrace -> (map TOp *** drop 1) . break (==LBrace)
          TOp t -> (map TOp *** (t:)) . span (op -> precedence op > precedence t && op /= LBrace)


          Or perhaps:



          (queue, stack) = (`runState` ) $ for ts $ case
          TNum t -> return [TNum t]
          TOp LBrace -> <$ modify (LBrace:)
          TOp RBrace -> do
          sstart <- state $ break (==LBrace)
          modify (drop 1)
          return $ map TOp sstart
          TOp t -> do
          ssops <- state $ span $ op -> precedence op > precedence t && op /= LBrace
          modify (t:)
          return $ map TOp ssops





          share|improve this answer





















          • Hey, thank you for your answer, but I can't get this code to compile. I've pasted it into the InToPost.hs file and compiled with ghc -dynamic -XLambdaCase -O2 InToPost.hs, but ghc spits out errors: Illegal tuple section: use TupleSections.
            – atmostmediocre
            4 hours ago











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210976%2finfix-to-postfix-notation-in-haskell-shunting-yard-algorithm%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          main :: IO ()
          main = do
          line <- getLine
          putStrLn $ case traverse str2tok $ splitTok line of
          Left s -> s
          Right ts -> unwords $ map tok2str $ shuntYard ts

          -- shuntYard (Token Buffer) = new Token Queue
          shuntYard :: [Token] -> [Token]
          shuntYard ts = concat queue ++ stack where
          (queue, stack) = (`runState` ) $ for ts $ state . case
          TNum t -> ([TNum t],)
          TOp LBrace -> (,) . (LBrace :)
          TOp RBrace -> (map TOp *** drop 1) . break (==LBrace)
          TOp t -> (map TOp *** (t:)) . span (op -> precedence op > precedence t && op /= LBrace)


          Or perhaps:



          (queue, stack) = (`runState` ) $ for ts $ case
          TNum t -> return [TNum t]
          TOp LBrace -> <$ modify (LBrace:)
          TOp RBrace -> do
          sstart <- state $ break (==LBrace)
          modify (drop 1)
          return $ map TOp sstart
          TOp t -> do
          ssops <- state $ span $ op -> precedence op > precedence t && op /= LBrace
          modify (t:)
          return $ map TOp ssops





          share|improve this answer





















          • Hey, thank you for your answer, but I can't get this code to compile. I've pasted it into the InToPost.hs file and compiled with ghc -dynamic -XLambdaCase -O2 InToPost.hs, but ghc spits out errors: Illegal tuple section: use TupleSections.
            – atmostmediocre
            4 hours ago
















          1














          main :: IO ()
          main = do
          line <- getLine
          putStrLn $ case traverse str2tok $ splitTok line of
          Left s -> s
          Right ts -> unwords $ map tok2str $ shuntYard ts

          -- shuntYard (Token Buffer) = new Token Queue
          shuntYard :: [Token] -> [Token]
          shuntYard ts = concat queue ++ stack where
          (queue, stack) = (`runState` ) $ for ts $ state . case
          TNum t -> ([TNum t],)
          TOp LBrace -> (,) . (LBrace :)
          TOp RBrace -> (map TOp *** drop 1) . break (==LBrace)
          TOp t -> (map TOp *** (t:)) . span (op -> precedence op > precedence t && op /= LBrace)


          Or perhaps:



          (queue, stack) = (`runState` ) $ for ts $ case
          TNum t -> return [TNum t]
          TOp LBrace -> <$ modify (LBrace:)
          TOp RBrace -> do
          sstart <- state $ break (==LBrace)
          modify (drop 1)
          return $ map TOp sstart
          TOp t -> do
          ssops <- state $ span $ op -> precedence op > precedence t && op /= LBrace
          modify (t:)
          return $ map TOp ssops





          share|improve this answer





















          • Hey, thank you for your answer, but I can't get this code to compile. I've pasted it into the InToPost.hs file and compiled with ghc -dynamic -XLambdaCase -O2 InToPost.hs, but ghc spits out errors: Illegal tuple section: use TupleSections.
            – atmostmediocre
            4 hours ago














          1












          1








          1






          main :: IO ()
          main = do
          line <- getLine
          putStrLn $ case traverse str2tok $ splitTok line of
          Left s -> s
          Right ts -> unwords $ map tok2str $ shuntYard ts

          -- shuntYard (Token Buffer) = new Token Queue
          shuntYard :: [Token] -> [Token]
          shuntYard ts = concat queue ++ stack where
          (queue, stack) = (`runState` ) $ for ts $ state . case
          TNum t -> ([TNum t],)
          TOp LBrace -> (,) . (LBrace :)
          TOp RBrace -> (map TOp *** drop 1) . break (==LBrace)
          TOp t -> (map TOp *** (t:)) . span (op -> precedence op > precedence t && op /= LBrace)


          Or perhaps:



          (queue, stack) = (`runState` ) $ for ts $ case
          TNum t -> return [TNum t]
          TOp LBrace -> <$ modify (LBrace:)
          TOp RBrace -> do
          sstart <- state $ break (==LBrace)
          modify (drop 1)
          return $ map TOp sstart
          TOp t -> do
          ssops <- state $ span $ op -> precedence op > precedence t && op /= LBrace
          modify (t:)
          return $ map TOp ssops





          share|improve this answer












          main :: IO ()
          main = do
          line <- getLine
          putStrLn $ case traverse str2tok $ splitTok line of
          Left s -> s
          Right ts -> unwords $ map tok2str $ shuntYard ts

          -- shuntYard (Token Buffer) = new Token Queue
          shuntYard :: [Token] -> [Token]
          shuntYard ts = concat queue ++ stack where
          (queue, stack) = (`runState` ) $ for ts $ state . case
          TNum t -> ([TNum t],)
          TOp LBrace -> (,) . (LBrace :)
          TOp RBrace -> (map TOp *** drop 1) . break (==LBrace)
          TOp t -> (map TOp *** (t:)) . span (op -> precedence op > precedence t && op /= LBrace)


          Or perhaps:



          (queue, stack) = (`runState` ) $ for ts $ case
          TNum t -> return [TNum t]
          TOp LBrace -> <$ modify (LBrace:)
          TOp RBrace -> do
          sstart <- state $ break (==LBrace)
          modify (drop 1)
          return $ map TOp sstart
          TOp t -> do
          ssops <- state $ span $ op -> precedence op > precedence t && op /= LBrace
          modify (t:)
          return $ map TOp ssops






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 20 hours ago









          GurkenglasGurkenglas

          2,808511




          2,808511












          • Hey, thank you for your answer, but I can't get this code to compile. I've pasted it into the InToPost.hs file and compiled with ghc -dynamic -XLambdaCase -O2 InToPost.hs, but ghc spits out errors: Illegal tuple section: use TupleSections.
            – atmostmediocre
            4 hours ago


















          • Hey, thank you for your answer, but I can't get this code to compile. I've pasted it into the InToPost.hs file and compiled with ghc -dynamic -XLambdaCase -O2 InToPost.hs, but ghc spits out errors: Illegal tuple section: use TupleSections.
            – atmostmediocre
            4 hours ago
















          Hey, thank you for your answer, but I can't get this code to compile. I've pasted it into the InToPost.hs file and compiled with ghc -dynamic -XLambdaCase -O2 InToPost.hs, but ghc spits out errors: Illegal tuple section: use TupleSections.
          – atmostmediocre
          4 hours ago




          Hey, thank you for your answer, but I can't get this code to compile. I've pasted it into the InToPost.hs file and compiled with ghc -dynamic -XLambdaCase -O2 InToPost.hs, but ghc spits out errors: Illegal tuple section: use TupleSections.
          – atmostmediocre
          4 hours ago


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210976%2finfix-to-postfix-notation-in-haskell-shunting-yard-algorithm%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Список кардиналов, возведённых папой римским Каликстом III

          Deduzione

          Mysql.sock missing - “Can't connect to local MySQL server through socket”