I have the following stack class:
newtype Stack my_stack = Stack [my_stack] deriving Show
getSize :: Stack my_stack -> Int
getSize (Stack []) = 0
getSize (Stack (x:xs)) = 1 + getSize (Stack xs)
push :: my_stack -> Stack my_stack -> Stack my_stack
push x (Stack xs) = Stack (x:xs)
pop :: Stack my_stack -> Stack my_stack
pop (Stack (x:xs)) = Stack xs
getTop :: Stack my_stack -> my_stack
getTop (Stack (x:xs)) = x
however when I try to use the getTop
function, I get the Non-exhaustive patterns in function getTop
error. How can I declare the base case (which I assume is empty case?) for the getTop
function so I won't be getting non-exhaustive pattern errors? Thank you!
Your function is unsafe right now. That warning is (correctly) notifying you that you don't handle the empty-stack case. Now, the question is: what do you want to do if the user calls getTop
with an empty stack? You've got a few options. I'll sort them in roughly descending order of my preference.
Maybe
If we have a value that may or may not exist, the idiomatic approach is to return Maybe
. Maybe
is a special type that may or may not contain a value, and it's up to the caller to decide what to do with it. They might themselves opt to return a Maybe
, or they might provide a default value, or they might just show the user an error. But the type system will enforce that they handle the situation.
getTop :: Stack my_stack -> Maybe my_stack
getTop (Stack []) = Nothing
getTop (Stack (x:xs)) = Just x
This is perfectly safe and gives the caller total control.
Instead, you can require the user to specify the value they want if the stack is empty.
getTop :: my_stack -> Stack my_stack -> my_stack
getTop orelse (Stack []) = orelse
getTop _ (Stack (x:xs)) = x
This is still perfectly safe, like the previous solution, but in my opinion it's more awkward than an Option
. The type signature Stack my_stack -> Maybe my_stack
is very clearly indicative of what the function does: it takes a stack and might return a value from it. The type signature my_stack -> Stack my_stack -> my_stack
is more nebulous: are we adding a value to the stack, are we returning a default, what are we doing? Further, if the user actually wants a Maybe
, there may not be a suitable default value that's distinguishable from "nothing was on the stack".
This is not idiomatic Haskell and I do not recommend doing it in production. But if you're just writing some short code for personal practice, it can be useful for hacking.
getTop :: Stack my_stack -> my_stack
getTop (Stack []) = error "Empty stack in getTop"
getTop (Stack (x:xs)) = x
error
is a special function that has signature String -> a
(for any a
). You provide it with an error message and it... well, it crashes your program. There are technically ways of catching an error
, but they're awkward and have a lot of difficult quirks, so generally you should regard error
as a hard crash and only use it if there's no possibility for recovery. Hence, I don't recommend it in this case, as "the stack was empty" is very much a recoverable condition.