F# Reverse Polish notation (RPN) Calculator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System | |
type Token = | |
| Number of int | |
| UnaryOperator of (int -> int -> int) | |
let tryCharToToken a = | |
match (Int32.TryParse a) with | |
| (true, num) -> Some (Number num) | |
| (false, _) -> | |
match a with | |
| "*" -> Some (UnaryOperator (*)) | |
| "+" -> Some (UnaryOperator (+)) | |
| _ -> None | |
let tryProcessRpn equation = | |
let extractResult stack = | |
match stack with | |
| x :: [] -> Some x | |
| _ -> None | |
let rec processRec input stack = | |
match input with | |
| [] -> extractResult stack | |
| (Number x) :: xs -> processRec xs (x :: stack) | |
| (UnaryOperator op) :: xs -> applyOperator xs op stack | |
and applyOperator input operator stack = | |
match stack with | |
| l :: r :: rs -> processRec input ((operator l r) :: rs) | |
| _ -> None | |
processRec equation [] | |
let evalRpn (s : String) = | |
let tokens = (s.Split [|' '|]) |> Array.toList | |
List.choose tryCharToToken tokens | |
|> tryProcessRpn | |
// Tests | |
let testExp exp expected = | |
match (evalRpn exp) with | |
| Some n -> | |
match expected with | |
| Some e -> if e = n then printf "." else printfn "\nExpected %i got %i for %s" e n exp | |
| None -> printfn "\nExpected None got %i for %s" n exp | |
| None -> | |
match expected with | |
| Some e -> printfn "\nExpected %i got None for %s" e exp | |
| None -> printf "." | |
let test () = | |
printfn "Running tests" | |
testExp "3 2 1 + *" (Some 9) | |
testExp "1 2 3" None | |
testExp "+" None | |
testExp "1 2 + +" (Some 3) | |
printfn "\nDone" | |
test () |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment