random-stuff/Stackulator.fs

101 lines
3.0 KiB
Forth
Raw Normal View History

2020-08-12 19:31:12 +00:00
open System
open System.Numerics
type Stack = StackContents of Complex list
let splitPart (what:char) index (stringIn:string) = stringIn.Split(what).[index]
let spliti = splitPart 'i'
let firstInSpliti = spliti 0
let secondInSpliti = spliti 1
let isDoubleAsString text = System.Double.TryParse text |> fst
let doubleFromString text = System.Double.TryParse text |> snd
let isImaginaryAsString (text:string) =
match text.Contains("i") with
| false -> false
| true ->
let normalPart = firstInSpliti text
isDoubleAsString normalPart
let imaginaryFromString text =
let imaginaryPart = doubleFromString (firstInSpliti text)
Complex(0.0, imaginaryPart)
let showStack (StackContents contents) =
printfn "%A" contents // Print unpacked StackContents with formatting string
StackContents (contents) // Repack the StackContents
let push value (StackContents contents) =
StackContents (value::contents)
let pop (StackContents contents) =
match contents with
| top::rest -> // Separate top from rest
(top, StackContents rest) // Stack contents must be the StackContents type.
| [] -> // Check for stack underflow
failwith "Stack underflow"
let binary func stack =
let x, newStack = pop stack
let y, newestStack = pop newStack
let z = func y x // This is deliberately swapped, because we are working on a stack
push z newestStack
let unary func stack =
let x, newStack = pop stack
push (func x) stack
let dup stack =
let x, _ = pop stack // Drop the new stack, we want to duplicate "x"
push x stack
let swap stack =
let x, newStack = pop stack
let y, newerStack = pop newStack
push y (push x newerStack)
let drop stack =
let _, newStack = pop stack // Pop one off the top and ignore it
newStack
let numberInput value stack = push value stack
let add = binary (+)
let multiply = binary (*)
let subtract = binary (-)
let divide = binary (/)
let negate = unary (fun x -> -(x))
let square = unary (fun x -> x * x)
let cube = dup >> dup >> multiply >> multiply
let exponent = binary ( ** )
let show stack =
let value, _ = pop(stack)
printfn "%A" value
stack // We're going to keep the same stack as before.
let empty = StackContents []
let splitString (text:string) = text.Split ' '
let processTokenString stack token =
match token with
| "*" -> stack |> multiply
| "+" -> stack |> add
| "/" -> stack |> divide
| "+-" -> stack |> negate
| "sqr" -> stack |> square
| "cub" -> stack |> cube
| "**" | "^" -> stack |> exponent
| _ when isDoubleAsString token ->
let doubleInString = doubleFromString token
numberInput (Complex(doubleInString, 0.0)) stack
| _ when isImaginaryAsString token ->
let imaginaryInString = imaginaryFromString token
numberInput imaginaryInString stack
| _ -> showStack stack // For easier debugging.
Console.Write("Please enter your expression here: ")
let userExpression = Console.ReadLine()
let splitExpression = splitString userExpression
let resultantStack = List.fold processTokenString (empty) (Array.toList splitExpression) |> showStack