你的函数有问题的部分是| otherwise = Descending。根据您的函数定义,如果列表中有两个连续的示例,例如x >= y,则该函数为降序。这不是True:如果 all 两个连续的元素 x > y(或 x >= y,如果您不要求它严格降序,则函数正在下降) .
此外,这里还有一个问题是一个包含一个元素(或没有元素)的列表可以被视为Ascending 和Descending。所以我认为我们要做的第一件事就是定义一些语义。我们可以决定使输出成为TypeOfSort 项目的列表,或者我们可以决定扩展TypeOfSort 的选项数量。
在这个答案中,我将选择最后一个选项。我们可以将TypeOfSort 扩展为:
data TypeOfSort = Ascending | Descending | Both | NotSorted
deriving (Show)
现在我们可以处理函数本身了。这里的基本情况当然是空列表[] 和一个元素列表[_]:
sorted [] = Both
sorted [_] = Both
现在我们需要定义归纳案例。列表何时升序排序?如果所有元素(严格)大于前一个元素。类似地,如果所有元素(严格)小于前一个元素,则列表按降序排序。现在让我们假设严格性。以后修改函数定义很容易。
因此,如果我们有一个包含两个或多个元素的列表,如果以第二个元素开头的列表是 Ascending 或 Both 和 x < y,则列表是 Ascending,或者换句话说:
sorted (x:y:xs) | Both <- sort_yxs, x < y = Ascending
| Ascending <- sort_yxs, x < y = Ascending
where sort_yxs = sorted (y:xs)
降序也是如此:如果列表的其余部分按降序排列,并且第一个元素大于第二个元素,则列表按降序排列:
| Both <- sort_yxs, x > y = Descending
| Ascending <- sort_yxs, > y = Descending
where sort_yxs = sorted (y:xs)
在所有剩余的情况下,这意味着列表的某些部分是Ascending,某些部分是Descending,因此列表是NotSorted。
| otherwise = NotSorted
或将这些放在一起:
sorted [] = Both
sorted [_] = Both
sorted (x:y:xs) | Both <- sort_yxs, x < y = Ascending
| Ascending <- sort_yxs, x < y = Ascending
| Both <- sort_yxs, x > y = Descending
| Ascending <- sort_yxs, x > y = Descending
| otherwise = NotSorted
where sort_yxs = sorted (y:xs)
重构:使TypeOfSort 成为Monoid
上面的定义包含很多边缘情况,这使得编写一个简单的程序变得很困难。我们可以通过引入一些实用函数来简化它。例如,这可以通过定义一个接受两个TypeOfSorts 然后返回交集的函数来完成。这样的函数可能如下所示:
intersect Both x = x
intersect x Both = x
intersect Ascending Ascending = Ascending
intersect Descending Descending = Descending
intersect _ _ = NotSorted
这实际上形成了一个以Both 为标识元素的monoid:
instance Monoid where
mappend Both x = x
mappend x Both = x
mappend Ascending Ascending = Ascending
mappend Descending Descending = Descending
mappend _ _ = NotSorted
mempty = Both
现在我们可以将定义改写为:
sorted [] = Both
sorted [_] = Both
sorted (x:y:ys) | x > y = mappend rec Ascending
| x < y = mappend rec Descending
| otherwise = NotSorted
where rec = sorted (y:ys)