Haskell Selectionsort功能,但带有运算符

Haskell Selectionsort功能,但带有运算符,haskell,Haskell,我试图写一个Selectionsort,但这次需要一个操作符,并根据它进行排序,例如 *Main> ssort (<) [2,8,4,6,3,9,7] [2,3,4,6,7,8,9] *Main> ssort (>) [2,8,4,6,2,6,7] [9,8,7,6,4,3,2] 现在的问题是,即使操作符是(>),数字也会被添加到第一个操作符中。 错误是 Couldn't match type `t -> [t] -> t' with `[t]'

我试图写一个Selectionsort,但这次需要一个操作符,并根据它进行排序,例如

*Main> ssort (<) [2,8,4,6,3,9,7] [2,3,4,6,7,8,9]
*Main> ssort (>) [2,8,4,6,2,6,7] [9,8,7,6,4,3,2]
现在的问题是,即使操作符是(>),数字也会被添加到第一个操作符中。 错误是

Couldn't match type `t -> [t] -> t' with `[t]'
      Expected type: [t] -> [t]

首先,始终向函数添加类型签名。在定义它们之前。这使得您所做的事情更加清晰,不仅对阅读您的代码的其他人如此,对您自己也是如此。因此,如果默认排序为

sort :: Ord a => [a] -> [a]
现在您不再需要Ord a(因为比较函数是用户提供的,而不是从全局实例推断出来的),但是您确实需要这种比较。
()
的类型是
Ord a=>a->a->Bool
。同样,我们不再关心
Ord
,但是
a->a->Bool
仍然正确。即

ssort :: (a -> a -> Bool) -> [a] -> [a]
…实际上,因为您正在使用
delete
,所以仍然需要
Eq

ssort :: Eq a => (a -> a -> Bool) -> [a] -> [a]
…虽然我认为这不是必要的

既然您有了两个参数,那么您的子句应该同时使用这两个参数,即

ssort (...) (...) = (...)
第一个仍然正确:

ssort _ [] = []
但现在来看一个有趣的问题:

ssort f (x:xs) = f x : ssort rest
好的,
fx
在这里没有意义。这里需要一个值,但已经部分应用了比较函数。比较函数只会给出比较结果,即布尔值,但即使如此,也需要提供两个参数

我想你真的想写

ssort f (x:xs) = val : ssort rest
这实际上是一个很好的尝试——如果我们正确定义
val
。但是

       val = f x xs
显然,这并不能解决问题
f
将简单地告诉您两个值中哪一个更大,但这里您给出了一个完整的列表。您可以做的是,查看
x
是否
f
-小于列表中的所有值

  where isxLeast = all (f x) xs
好的,那么如果它是最小的呢?这很简单,因为
val
应该是
x
,对吗?以下定义表示并将至少进行类型检查:

ssort _ [] = []
ssort f (x:xs) = val : ssort rest
 where val
        | all (f x) xs  = x
       rest = delete val xs  -- actually unnecessary in this case,
                             -- because val=x is already split off
问题是,只有当
x
确实是最小的元素,然后在递归中一次又一次,它才起作用。换句话说,它只在列表已经排序的情况下才有效

您需要做的当然是提供正确的
val
,如果它不在列表的最前面。因此,首先我们不妨放弃列表头上的模式匹配:

ssort f xs = val : ssort rest
 where val = findLeastOf f xs
       rest = delete val xs

findLeastOf :: (a -> a -> Bool) -> [a] -> a
findLeastOf f (x:xs)
  | all (f x) xs  = x
  | otherwise     = _
你应该能够自己完成这项工作。(请注意,如果您在
findLeastOf
中递归
xs
,它将非常低效,O(n2),导致排序的复杂性为O(n3)。但现在您可能不必担心这一点。)

ssort f xs = val : ssort rest
 where val = findLeastOf f xs
       rest = delete val xs

findLeastOf :: (a -> a -> Bool) -> [a] -> a
findLeastOf f (x:xs)
  | all (f x) xs  = x
  | otherwise     = _