Let's say I'm trying to build a simple Stack in F# as follows:
type Stack =
| Empty
| Stack of String list
(I know I can define it recursively but for this example, let's assume I'd like to have a list in there)
Then I define a push operation like this:
let push item deck =
match deck with
| Empty -> Stack [item]
| Stack d -> Stack (item::d)
But when I reach the pop operation... I'm not having success. I wanted to do something like this:
let pop (Stack d) =
match d with
| h::[] -> h,Empty
| h::t -> h,(Stack t)
For now, let's also try to ignore the fact that I might want a peek/pop pair of operations instead of returning a tuple. What I wanted to try was to write a pop operation which would only accept a Stack which is not empty in the first place.
In other words, I only wanted this function to accept one of the cases of the Discriminated Union. However, I immediately get the warning: "Incomplete pattern matches on this expression. For example, the value 'Empty' may indicate a case not covered by the pattern(s)'.
As expected (after the warning), the following code:
let empty = Empty
let s,st = pop empty
... compiles and fails at run time. I wanted it to fail at compile time.
I'm aware I could use other options for this, such as:
let pop stack =
match stack with
| Empty -> None, Empty
| Stack (h::[]) -> Some h,Empty
| Stack (h::t) -> Some h,(Stack t)
or:
let pop stack =
match stack with
| Empty -> Error "Empty Stack"
| Stack (h::[]) -> Ok (h,Empty)
| Stack (h::t) -> Ok (h,(Stack t))
(and on both of these cases I might not even need the Empty case at all...)
But I was trying to make something more restrictive. So... what am I missing here? Is there a way to achieve what I was attempting? Does it even make any sense to want that?