Haskell:堆栈中的非详尽模式
Haskell: Non-exhaustive patterns in 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
然而,当我尝试使用 getTop
函数时,出现 Non-exhaustive patterns in function getTop
错误。我如何为 getTop
函数声明基本情况(我假设是空情况?),这样我就不会得到非详尽的模式错误?谢谢!
此声明:
getTop (Stack (x:xs)) = x
意思是:“当getTop
的参数是一个Stack
,它包含一个由头x
和尾xs
组成的列表,结果是x
"
但是如果参数是一个包含空列表的 Stack
怎么办?您尚未定义在这种情况下应该发生什么,因此会发生错误。
因此您需要针对该情况的模式匹配:
getTop (Stack (x:xs)) = x
getTop (Stack []) = ???
但问题是:在那种情况下 getTop
的结果应该是什么?只有您可以根据您的具体情况来决定。对于它的价值,一个常见的模式是 return a Maybe my_stack
代替:
getTop :: Stack my_stack -> Maybe my_stack
getTop (Stack (x:xs)) = Just x
getTop (Stack []) = Nothing
您的函数目前不安全。该警告是(正确地)通知您您不处理空堆栈情况。现在,问题是:如果用户用空堆栈调用 getTop
,你想做什么?你有几个选择。我会按照我的喜好大致降序排列它们。
1。 ReturnMaybe
如果我们有一个可能存在也可能不存在的值,惯用的方法是 return Maybe
。 Maybe
是一种特殊类型,可能包含也可能不包含值,由调用者决定如何处理它。他们自己可能会选择 return a Maybe
,或者他们可能会提供一个默认值,或者他们可能只是向用户显示一个错误。但是类型系统会强制他们处理这种情况。
getTop :: Stack my_stack -> Maybe my_stack
getTop (Stack []) = Nothing
getTop (Stack (x:xs)) = Just x
这是绝对安全的,并且可以让调用者完全控制。
2。强制用户提供默认值
相反,如果堆栈为空,您可以要求用户指定他们想要的值。
getTop :: my_stack -> Stack my_stack -> my_stack
getTop orelse (Stack []) = orelse
getTop _ (Stack (x:xs)) = x
这仍然是非常安全的,就像以前的解决方案一样,但在我看来它比 Option
更尴尬。类型签名 Stack my_stack -> Maybe my_stack
非常清楚地表明了函数的作用:它需要一个堆栈,并且可能 return 从中得到一个值。类型签名 my_stack -> Stack my_stack -> my_stack
更加模糊:我们是在向堆栈添加一个值,我们是在 return 默认值,我们在做什么?此外,如果用户实际上 想要 Maybe
,则可能没有合适的默认值来区别于“堆栈上什么都没有”。
3。抛出错误
这是不是惯用的Haskell,我不建议在生产中这样做。但是如果你只是为了个人练习而写一些简短的代码,它可能对黑客有用。
getTop :: Stack my_stack -> my_stack
getTop (Stack []) = error "Empty stack in getTop"
getTop (Stack (x:xs)) = x
error
是一个具有签名 String -> a
的特殊函数(对于任何 a
)。您向它提供一条错误消息,然后它……好吧,它使您的程序崩溃。技术上有捕捉 error
的方法,但它们很笨拙并且有很多困难的怪癖,所以通常你应该将 error
视为硬崩溃,并且只有在 [=47= 时才使用它]没有 恢复的可能性。因此,在这种情况下我不推荐它,因为“堆栈为空”是一个非常可恢复的条件。
我有以下堆栈 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
然而,当我尝试使用 getTop
函数时,出现 Non-exhaustive patterns in function getTop
错误。我如何为 getTop
函数声明基本情况(我假设是空情况?),这样我就不会得到非详尽的模式错误?谢谢!
此声明:
getTop (Stack (x:xs)) = x
意思是:“当getTop
的参数是一个Stack
,它包含一个由头x
和尾xs
组成的列表,结果是x
"
但是如果参数是一个包含空列表的 Stack
怎么办?您尚未定义在这种情况下应该发生什么,因此会发生错误。
因此您需要针对该情况的模式匹配:
getTop (Stack (x:xs)) = x
getTop (Stack []) = ???
但问题是:在那种情况下 getTop
的结果应该是什么?只有您可以根据您的具体情况来决定。对于它的价值,一个常见的模式是 return a Maybe my_stack
代替:
getTop :: Stack my_stack -> Maybe my_stack
getTop (Stack (x:xs)) = Just x
getTop (Stack []) = Nothing
您的函数目前不安全。该警告是(正确地)通知您您不处理空堆栈情况。现在,问题是:如果用户用空堆栈调用 getTop
,你想做什么?你有几个选择。我会按照我的喜好大致降序排列它们。
1。 ReturnMaybe
如果我们有一个可能存在也可能不存在的值,惯用的方法是 return Maybe
。 Maybe
是一种特殊类型,可能包含也可能不包含值,由调用者决定如何处理它。他们自己可能会选择 return a Maybe
,或者他们可能会提供一个默认值,或者他们可能只是向用户显示一个错误。但是类型系统会强制他们处理这种情况。
getTop :: Stack my_stack -> Maybe my_stack
getTop (Stack []) = Nothing
getTop (Stack (x:xs)) = Just x
这是绝对安全的,并且可以让调用者完全控制。
2。强制用户提供默认值
相反,如果堆栈为空,您可以要求用户指定他们想要的值。
getTop :: my_stack -> Stack my_stack -> my_stack
getTop orelse (Stack []) = orelse
getTop _ (Stack (x:xs)) = x
这仍然是非常安全的,就像以前的解决方案一样,但在我看来它比 Option
更尴尬。类型签名 Stack my_stack -> Maybe my_stack
非常清楚地表明了函数的作用:它需要一个堆栈,并且可能 return 从中得到一个值。类型签名 my_stack -> Stack my_stack -> my_stack
更加模糊:我们是在向堆栈添加一个值,我们是在 return 默认值,我们在做什么?此外,如果用户实际上 想要 Maybe
,则可能没有合适的默认值来区别于“堆栈上什么都没有”。
3。抛出错误
这是不是惯用的Haskell,我不建议在生产中这样做。但是如果你只是为了个人练习而写一些简短的代码,它可能对黑客有用。
getTop :: Stack my_stack -> my_stack
getTop (Stack []) = error "Empty stack in getTop"
getTop (Stack (x:xs)) = x
error
是一个具有签名 String -> a
的特殊函数(对于任何 a
)。您向它提供一条错误消息,然后它……好吧,它使您的程序崩溃。技术上有捕捉 error
的方法,但它们很笨拙并且有很多困难的怪癖,所以通常你应该将 error
视为硬崩溃,并且只有在 [=47= 时才使用它]没有 恢复的可能性。因此,在这种情况下我不推荐它,因为“堆栈为空”是一个非常可恢复的条件。