1

我是 Haskell 的新手,谁能建议我如何将 F# 中的以下程序重写为 Haskell,以便尽可能地相似。

不知道如何在 Haskell 中定义堆栈数据类型。

谢谢

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 +"))

想要有类似的东西:

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
4

2 回答 2

2

这是一个非常基本的翻译:

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 +"

由于.netStack不是纯的,我选择使用一个简单的列表作为替代,这当然意味着您必须通过计算线程化状态(堆栈)(这是那些let (v1,stck)...部分的工作)

我认为这对初学者来说是最简单的——如果你稍微进步一点,你可能会回来并使用 state-monad 重新实现它(实际上我用它完全伪装成 let's 使用它)使它更具可读性/美观

当然,您必须为您的运营商添加其他案例

评论

对于格式错误的输入,这将失败(就像你的版本一样) - 如果你愿意,你可以在Maybe(in pop, calcand eval) ...

让它更好一点

如果你自己实现这些案例,你会发现这些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

另请注意,您必须反转操作,因为您以错误的顺序弹出

如果你不介意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

这是一个例子:

λ> eval "3 5 + 2 - 3 /"
2.0
于 2015-07-29T13:47:00.220 回答
0

这个(非常流行的)教程解决了这个确切的问题:

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

于 2015-07-29T13:36:43.943 回答