-
Notifications
You must be signed in to change notification settings - Fork 0
/
Program.fs
99 lines (83 loc) · 2.7 KB
/
Program.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// For more information see https://aka.ms/fsharp-console-apps
module Calc
open System
(*
* A calculator expression is "x op y"
* Quick explanation of the calculator state machine:
* The initial state is "waiting for x" (wfx for short)
* Upon receiving x, the new state is "waiting for operator" (wfop)
* - The wfop state contains the value for x
* Upon receiving the operator, the new state is wfy
* - The wfy state contains the values for x and op
* Upon receiving y, the result is calculated, printed, and put into x. The new state is wfop.
* This loop continues until something invalid is entered as a number or operator
*)
type Operator =
| Plus
| Minus
| Times
| DividedBy
type CalcState =
| WaitingForX
| WaitingForOp of float
| WaitingForY of float * Operator
| Finished
let toOperator s =
match s with
| "+" -> Some Plus
| "-" -> Some Minus
| "*" -> Some Times
| "/" -> Some DividedBy
| _ -> None
let progressFromWfx =
printfn "Give a number"
let input = Console.ReadLine()
let inputAsFloat = Utils.parseFloat input
match inputAsFloat with
| Some(n) -> WaitingForOp n
| None -> Finished
let progressFromWfop x =
printfn "Give an operator (+, -, *, /)"
let input = Console.ReadLine()
let inputAsOperator = toOperator input
match inputAsOperator with
| None -> Finished
| Some(op) -> WaitingForY (x, op)
let calculate x (op:Operator) y =
match op with
| Plus -> x + y
| Minus -> x - y
| Times -> x * y
| DividedBy -> x / y
let transitionToWfop x op y =
let result = calculate x op y
printfn "Current result: %A" result
WaitingForOp result
let progressFromWfy x op =
printfn "Give a number"
let input = Console.ReadLine()
let inputAsFloat = Utils.parseFloat input
match inputAsFloat with
| Some(n) -> transitionToWfop x op n
| None -> Finished
let nextState state =
match state with
| WaitingForX -> progressFromWfx
| WaitingForOp(x) -> progressFromWfop x
| WaitingForY(x, op) -> progressFromWfy x op
| Finished -> Finished
let startLoop = fun () ->
// TODO: Is there a better way? Unfold needs both next element and next state
let inputSeq = Seq.unfold (fun state ->
match state with
| Finished -> None
| unfinishedState ->
let newState = nextState unfinishedState
Some (newState, newState)) WaitingForX
for _ in inputSeq do ()
[<EntryPoint>]
let calcMain argv =
printfn "I am a basic calculator"
startLoop()
printfn "Since you entered something invalid, I give up"
0