简体   繁体   English

F#的Haskell RPN计算器

[英]Haskell RPN calculator from F#

I am new at Haskell, could anyone suggest me how to rewrite folowing program in F# to Haskell so it will be as much as similar as possible. 我是Haskell的新手,有人可以建议我如何将F#中的跟踪程序重写为Haskell,以使它尽可能相似。

Don't know how to define stack data type in Haskell. 不知道如何在Haskell中定义堆栈数据类型。

Thanks 谢谢

let calc input (stck:Stack<double>) =
    match input with
        | "*" -> stck.Push(stck.Pop() * stck.Pop())
        | "+" -> stck.Push(stck.Pop() + stck.Pop())
        | "-" -> stck.Push(stck.Pop() - stck.Pop())
        | "/" -> stck.Push(stck.Pop() / stck.Pop())
        | _ -> stck.Push(System.Convert.ToDouble(input))

let evalu (inputStr:string) =
    let stk = Stack<double>()

    let elem = inputStr.Split([|' '|])

    Array.iter (fun ent -> calc ent stk) elem
    stk.Pop()

//Call
Console.WriteLine(evalu("3 5 +"))

Would like to have something like: 想拥有类似的东西:

calc input stck
    | input == '*' = stck.push(stck.pop * stck.pop)
    | input == '+' = stck.push(stck.pop + stck.pop)
    | input == '-' = stck.push(stck.pop - stck.pop)
    | input == '/' = stck.push(stck.pop / stck.pop)
    | otherwise   = stck.push(input)

main = calc "3 5 +" [] //Somehow do folding

here is a very basic translation: 这是一个非常基本的翻译:

module Main where

type Stack = [Double]

push :: Stack -> Double -> [Double]
push s v = v:s

pop :: Stack -> (Double, Stack)
pop []    = error "empty stack"
pop (v:s) = (v,s)

calc :: Stack -> String -> Stack
calc stck "+" = let (v1,stck') = pop stck
                    (v2,stck'') = pop stck'
                in push stck'' $ v1+v2
calc stck n = push stck $ read n

eval :: String -> Double
eval = head . foldl calc [] . words

main :: IO ()
main = print $ eval "3 5 +"

as .net's Stack is not pure I opted to use a simple list as an alternative, this of course means that you have to thread the state (the stack) through your calculations (that is the job of those let (v1,stck)... parts) 由于.net的Stack不是纯粹的,我选择使用简单列表作为替代,这当然意味着您必须通过计算来线程化状态 (堆栈)(这就是let (v1,stck)...的工作let (v1,stck)...零件)

I think this is the easiest one for an beginner - if you advanced a bit you might come back and reimplement this in using the state-monad (indeed I used it in disguise exactly with the let's) to make it a bit more readable/beautiful 我认为对于初学者来说这是最简单的方法-如果您进行了一些高级操作,您可能会回来并通过使用state-monad重新实现它(实际上我是在让我们伪装的情况下使用它),以使其更具可读性/美观

Of course you have to add the other cases for your operators 当然,您必须为操作员添加其他情况

remarks 备注

This will fail for malformed inputs (as would your version) - if you like you can sprinkle in Maybe (in pop , calc and eval ) ... 对于格式错误的输入(与您的版本一样),此操作将失败-如果您愿意,可以在Maybe (在popcalceval )撒上...

making it a bit nicer 使它更好一点

if you implement the cases yourself you will find that the let ... pop ... push stuff is repeating a lot - so let's DRY : 如果您自己实施案例,您会发现let ... pop ... push内容重复很多-因此让我们DRY

apply :: (Double -> Double -> Double) -> Stack -> Stack
apply op stack =
  let (a,stack')  = pop stack
      (b,stack'') = pop stack'
  in push stack'' (b `op` a)

calc :: Stack -> String -> Stack
calc stack "+" = apply (+) stack
calc stack "*" = apply (*) stack
calc stack "-" = apply (-) stack
calc stack "/" = apply (/) stack
calc stack n = push stack $ read n

also note that you have to reverse the operation because you pop in the wrong order 还请注意,由于弹出顺序错误,您必须撤消操作

if you don't mind flip ing: 如果您不介意flip

calc :: String -> Stack -> Stack
calc "+" = apply (+)
calc "*" = apply (*)
calc "-" = apply (-)
calc "/" = apply (/)
calc n   = flip push $ read n

eval :: String -> Double
eval = head . foldl (flip calc) [] . words

here is an example: 这是一个例子:

λ> eval "3 5 + 2 - 3 /"
2.0

This (very popular) tutorial tackles this exact problem: 这个(非常受欢迎的)教程解决了这个确切的问题:

http://learnyouahaskell.com/functionally-solving-problems#reverse-polish-notation-calculator http://learnyouahaskell.com/functionally-solving-problems#reverse-polish-notation-calculator

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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