1

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.

Don't know how to define stack data type in 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
MatejKr
  • 115
  • 12

2 Answers2

2

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)

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

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) ...

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:

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 fliping:

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
Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • Thanks. What is the meaning od stack' and stack'' – MatejKr Jul 29 '15 at 14:03
  • 1
    those are just *versions* of stack (it goes from `stack` to `stack'` to `stack''`) you will see this quite often - it's a bit like using `i1`, `i2`, ... it's not really a thing in the language - it's just a convention many people are using – Random Dev Jul 29 '15 at 15:45
  • 1
    here `stack'` is `stack` after you poped `a` and `stack''` is `stack'` after you poped `b` (so `a:b:stack'' == a:stack' == stack`) – Random Dev Jul 29 '15 at 15:46
  • @MatejKr Keep in mind that this solution fulfils your request to keep code "as much as similar as possible" to F#. This solution is not idiomatic in Haskell, IMHO. The last alternatives are closer to idiomatic Haskell, but I'd argue that using `pop` (which is a partial function) instead of pattern matching is not common, nor a good practice in Haskell. Feel free to study this code, but do not try to learn Haskell by translating from other languages. (This holds in general: learning language X by translating from Y is never a good idea) – chi Jul 29 '15 at 16:01
  • @chi yes of course something like `calc (b:a:stack) "+" = (a+b):stack` would be more idiomatic to haskell but that **is** already covered by LYAH (the link) so I thought it would be pointless to inlcude it *plus* I think using lists is a good approximation to stack and the `pop`, `push` stuff is just what .net/fsharp would do (partiality included) – Random Dev Jul 29 '15 at 16:15
  • @Carsten I completely agree. – chi Jul 29 '15 at 16:18
0

This (very popular) tutorial tackles this exact problem:

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

obadz
  • 889
  • 4
  • 10