Haskell参数 - 比较运算符

时间:2013-03-09 05:24:29

标签: haskell

我想定义一个函数,其参数包含一个列表和一个运算符。这就是我现在拥有的。我正在尝试定义一个可以找到最小值或最大值的高阶函数。

largest :: (a -> a -> Bool) -> a
largest = findType (>)

findType :: (a -> a -> Bool) -> [a] -> a
findType op [] = error "empty list"
findType op [x] = x
findType op (x:xs) 
    | x op maxTail = x
    | otherwise = maxTail
    where maxTail = findType op xs

但是,它目前无法使用。

3 个答案:

答案 0 :(得分:3)

您可以编写一个接受任何a -> a -> Bool函数参数的函数,也可以使用可比数据类型实现Ord类的事实。

这是一段代码,显示检查列表是否已排序的两种方法

option1 :: (a->a->Bool) -> [a] -> Bool
option1 op (a:b:ls) = op a b && option1 op (b:ls)
option1 op _ = True

option2 :: (Ord a) => Ordering -> [a] -> Bool
option2 op (a:b:ls) = compare a b == op && option2 op (b:ls)
option2 op _ = True

main = do
   let ls = [1, 2, 3]
   print $ option1 (<) ls
   print $ option2 LT ls

请注意,第二种方法需要使用Ordering数据类型,其中只有值LTEQGT(分别表示&lt;,=和&gt; )。您可以通过传递可接受的Ordering值列表或其他一些数据结构来使其更灵活,但是,在大多数情况下,第一个选项更合适。

答案 1 :(得分:1)

您的代码有两个不同的问题。让我们先解决生成编译器错误的问题。

您向findType提供了以下签名:

findType :: (a -> a -> Bool) -> [a] -> a

意图是从作为第二个参数给出的列表中提取绑定,作为第一个参数提供的排序谓词。

但是,在非常findType函数定义的最后一行中,您将maxTail绑定到表达式findType xs,这将省略谓词。

正确的路线当然是:

where maxTail = findType op xs

您的第二个错误与largest功能的签名有关,但我会让您确切地知道它是什么。

答案 2 :(得分:1)

GHC并不知道您希望将 op 函数用作代码中的运算符,您必须告诉他,但您怎么能这样做?

让我们考虑 elem 函数,这个函数取一个值和一个列表,并返回True或False,具体取决于该值是否存在于列表中。

elem :: Eq a => a -> [a] -> Bool
elem 2 [1,2,3] => True

基本上它被视为一个函数,如果你想将它们用作一个非常有用的运算符,你必须用`将它括起来。

2 `elem` [1,2,3] => True

如果在find子句的调用中将didierc的注释添加到where子句中,您将拥有一个正常工作的代码。

无论如何,将一个递归调用放入一个警卫是一个非常糟糕的主意,代码是最难读的,我不确定它是否会导致性能问题。您需要了解如何使用累加器,请查看this


注意
相反,当默认情况下将某个函数视为运算符时,要将其用作函数,只需将其与()括起来。

2 : [] => [2]

(:) 2 [] => [2]